@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,483 @@
1
+ import React, { useState, useCallback, useMemo, ReactNode } from 'react';
2
+ import {
3
+ Modal,
4
+ TextInput,
5
+ Stack,
6
+ Group,
7
+ Text,
8
+ UnstyledButton,
9
+ ThemeIcon,
10
+ Badge,
11
+ Kbd,
12
+ Box,
13
+ ScrollArea,
14
+ Divider,
15
+ Center,
16
+ Loader,
17
+ } from '@mantine/core';
18
+ import { useHotkeys } from '@mantine/hooks';
19
+ import { IconSearch, IconArrowRight } from '@tabler/icons-react';
20
+
21
+ // =============================================================================
22
+ // Types
23
+ // =============================================================================
24
+
25
+ export interface SpotlightAction {
26
+ /** ID único da ação */
27
+ id: string;
28
+ /** Título da ação */
29
+ title: string;
30
+ /** Descrição opcional */
31
+ description?: string;
32
+ /** Ícone */
33
+ icon?: ReactNode;
34
+ /** Grupo/categoria */
35
+ group?: string;
36
+ /** Atalho de teclado */
37
+ shortcut?: string[];
38
+ /** Callback ao selecionar */
39
+ onTrigger: () => void;
40
+ /** Desabilitado */
41
+ disabled?: boolean;
42
+ /** Palavras-chave para busca */
43
+ keywords?: string[];
44
+ /** Badge */
45
+ badge?: string;
46
+ /** Cor do badge */
47
+ badgeColor?: string;
48
+ }
49
+
50
+ export interface ArchbaseSpotlightProps {
51
+ /** Array de ações */
52
+ actions: SpotlightAction[];
53
+ /** Atalho para abrir (padrão: mod+K) */
54
+ shortcut?: string;
55
+ /** Placeholder da busca */
56
+ searchPlaceholder?: string;
57
+ /** Mensagem quando não encontra resultados */
58
+ nothingFoundMessage?: string;
59
+ /** Limite de resultados exibidos */
60
+ limit?: number;
61
+ /** Filtrar ações por permissão */
62
+ filterByPermission?: (action: SpotlightAction) => boolean;
63
+ /** Agrupar ações */
64
+ groupActions?: boolean;
65
+ /** Loading state */
66
+ loading?: boolean;
67
+ /** Aberto (controlado) */
68
+ opened?: boolean;
69
+ /** Callback ao mudar estado */
70
+ onOpenChange?: (opened: boolean) => void;
71
+ /** Fechar ao selecionar ação */
72
+ closeOnActionTrigger?: boolean;
73
+ /** Destacar match na busca */
74
+ highlightQuery?: boolean;
75
+ /** Ações recentes */
76
+ recentActions?: string[];
77
+ /** Callback ao usar ação (para rastrear recentes) */
78
+ onActionUsed?: (actionId: string) => void;
79
+ /** Máximo de ações recentes */
80
+ maxRecentActions?: number;
81
+ }
82
+
83
+ // =============================================================================
84
+ // Fuzzy Search
85
+ // =============================================================================
86
+
87
+ function fuzzyMatch(text: string, query: string): boolean {
88
+ const textLower = text.toLowerCase();
89
+ const queryLower = query.toLowerCase();
90
+
91
+ let queryIndex = 0;
92
+ for (let i = 0; i < textLower.length && queryIndex < queryLower.length; i++) {
93
+ if (textLower[i] === queryLower[queryIndex]) {
94
+ queryIndex++;
95
+ }
96
+ }
97
+
98
+ return queryIndex === queryLower.length;
99
+ }
100
+
101
+ function searchActions(actions: SpotlightAction[], query: string): SpotlightAction[] {
102
+ if (!query.trim()) return actions;
103
+
104
+ const queryLower = query.toLowerCase();
105
+
106
+ return actions.filter((action) => {
107
+ // Match title
108
+ if (action.title.toLowerCase().includes(queryLower)) return true;
109
+ if (fuzzyMatch(action.title, query)) return true;
110
+
111
+ // Match description
112
+ if (action.description?.toLowerCase().includes(queryLower)) return true;
113
+
114
+ // Match keywords
115
+ if (action.keywords?.some((kw) => kw.toLowerCase().includes(queryLower))) return true;
116
+
117
+ // Match group
118
+ if (action.group?.toLowerCase().includes(queryLower)) return true;
119
+
120
+ return false;
121
+ });
122
+ }
123
+
124
+ // =============================================================================
125
+ // Highlight Component
126
+ // =============================================================================
127
+
128
+ interface HighlightTextProps {
129
+ text: string;
130
+ query: string;
131
+ highlight?: boolean;
132
+ }
133
+
134
+ function HighlightText({ text, query, highlight = true }: HighlightTextProps) {
135
+ if (!highlight || !query.trim()) {
136
+ return <>{text}</>;
137
+ }
138
+
139
+ const parts = text.split(new RegExp(`(${query})`, 'gi'));
140
+
141
+ return (
142
+ <>
143
+ {parts.map((part, index) =>
144
+ part.toLowerCase() === query.toLowerCase() ? (
145
+ <Text key={index} span fw={700} c="blue">
146
+ {part}
147
+ </Text>
148
+ ) : (
149
+ <span key={index}>{part}</span>
150
+ )
151
+ )}
152
+ </>
153
+ );
154
+ }
155
+
156
+ // =============================================================================
157
+ // Action Item Component
158
+ // =============================================================================
159
+
160
+ interface ActionItemProps {
161
+ action: SpotlightAction;
162
+ query: string;
163
+ isSelected: boolean;
164
+ highlightQuery: boolean;
165
+ onClick: () => void;
166
+ }
167
+
168
+ function ActionItem({ action, query, isSelected, highlightQuery, onClick }: ActionItemProps) {
169
+ return (
170
+ <UnstyledButton
171
+ onClick={onClick}
172
+ disabled={action.disabled}
173
+ style={{
174
+ display: 'block',
175
+ width: '100%',
176
+ padding: '10px 12px',
177
+ borderRadius: 'var(--mantine-radius-sm)',
178
+ backgroundColor: isSelected
179
+ ? 'var(--mantine-color-blue-light)'
180
+ : 'transparent',
181
+ opacity: action.disabled ? 0.5 : 1,
182
+ cursor: action.disabled ? 'not-allowed' : 'pointer',
183
+ }}
184
+ >
185
+ <Group gap="sm" wrap="nowrap">
186
+ {action.icon && (
187
+ <ThemeIcon variant="light" size="md" color="blue">
188
+ {action.icon}
189
+ </ThemeIcon>
190
+ )}
191
+ <Box style={{ flex: 1 }}>
192
+ <Group gap="xs">
193
+ <Text size="sm" fw={500}>
194
+ <HighlightText
195
+ text={action.title}
196
+ query={query}
197
+ highlight={highlightQuery}
198
+ />
199
+ </Text>
200
+ {action.badge && (
201
+ <Badge size="xs" color={action.badgeColor}>
202
+ {action.badge}
203
+ </Badge>
204
+ )}
205
+ </Group>
206
+ {action.description && (
207
+ <Text size="xs" c="dimmed">
208
+ <HighlightText
209
+ text={action.description}
210
+ query={query}
211
+ highlight={highlightQuery}
212
+ />
213
+ </Text>
214
+ )}
215
+ </Box>
216
+ {action.shortcut && (
217
+ <Group gap={4}>
218
+ {action.shortcut.map((key, index) => (
219
+ <Kbd key={index} size="xs">
220
+ {key}
221
+ </Kbd>
222
+ ))}
223
+ </Group>
224
+ )}
225
+ {isSelected && <IconArrowRight size={16} style={{ opacity: 0.5 }} />}
226
+ </Group>
227
+ </UnstyledButton>
228
+ );
229
+ }
230
+
231
+ // =============================================================================
232
+ // ArchbaseSpotlight Component
233
+ // =============================================================================
234
+
235
+ export function ArchbaseSpotlight({
236
+ actions,
237
+ shortcut = 'mod+K',
238
+ searchPlaceholder = 'Buscar ações...',
239
+ nothingFoundMessage = 'Nenhuma ação encontrada',
240
+ limit = 10,
241
+ filterByPermission,
242
+ groupActions = true,
243
+ loading = false,
244
+ opened: controlledOpened,
245
+ onOpenChange,
246
+ closeOnActionTrigger = true,
247
+ highlightQuery = true,
248
+ recentActions = [],
249
+ onActionUsed,
250
+ maxRecentActions = 5,
251
+ }: ArchbaseSpotlightProps) {
252
+ const [internalOpened, setInternalOpened] = useState(false);
253
+ const [query, setQuery] = useState('');
254
+ const [selectedIndex, setSelectedIndex] = useState(0);
255
+
256
+ const isControlled = controlledOpened !== undefined;
257
+ const opened = isControlled ? controlledOpened : internalOpened;
258
+
259
+ const setOpened = useCallback(
260
+ (value: boolean) => {
261
+ if (isControlled) {
262
+ onOpenChange?.(value);
263
+ } else {
264
+ setInternalOpened(value);
265
+ }
266
+ if (!value) {
267
+ setQuery('');
268
+ setSelectedIndex(0);
269
+ }
270
+ },
271
+ [isControlled, onOpenChange]
272
+ );
273
+
274
+ // Register global shortcut
275
+ useHotkeys([[shortcut, () => setOpened(true)]]);
276
+
277
+ // Filter and search actions
278
+ const filteredActions = useMemo(() => {
279
+ let result = actions;
280
+
281
+ // Apply permission filter
282
+ if (filterByPermission) {
283
+ result = result.filter(filterByPermission);
284
+ }
285
+
286
+ // Apply search
287
+ result = searchActions(result, query);
288
+
289
+ // Apply limit
290
+ return result.slice(0, limit);
291
+ }, [actions, filterByPermission, query, limit]);
292
+
293
+ // Group actions
294
+ const groupedActions = useMemo(() => {
295
+ if (!groupActions) return { '': filteredActions };
296
+
297
+ const groups: Record<string, SpotlightAction[]> = {};
298
+
299
+ // Add recent actions group
300
+ if (!query && recentActions.length > 0) {
301
+ const recent = actions
302
+ .filter((a) => recentActions.includes(a.id))
303
+ .slice(0, maxRecentActions);
304
+ if (recent.length > 0) {
305
+ groups['Recentes'] = recent;
306
+ }
307
+ }
308
+
309
+ // Group remaining actions
310
+ filteredActions.forEach((action) => {
311
+ const group = action.group || 'Ações';
312
+ if (!groups[group]) {
313
+ groups[group] = [];
314
+ }
315
+ groups[group].push(action);
316
+ });
317
+
318
+ return groups;
319
+ }, [filteredActions, groupActions, query, recentActions, actions, maxRecentActions]);
320
+
321
+ // Flat list for keyboard navigation
322
+ const flatActions = useMemo(() => {
323
+ return Object.values(groupedActions).flat();
324
+ }, [groupedActions]);
325
+
326
+ // Handle action trigger
327
+ const handleActionTrigger = useCallback(
328
+ (action: SpotlightAction) => {
329
+ if (action.disabled) return;
330
+
331
+ action.onTrigger();
332
+ onActionUsed?.(action.id);
333
+
334
+ if (closeOnActionTrigger) {
335
+ setOpened(false);
336
+ }
337
+ },
338
+ [closeOnActionTrigger, setOpened, onActionUsed]
339
+ );
340
+
341
+ // Keyboard navigation
342
+ const handleKeyDown = useCallback(
343
+ (event: React.KeyboardEvent) => {
344
+ if (event.key === 'ArrowDown') {
345
+ event.preventDefault();
346
+ setSelectedIndex((prev) => Math.min(prev + 1, flatActions.length - 1));
347
+ } else if (event.key === 'ArrowUp') {
348
+ event.preventDefault();
349
+ setSelectedIndex((prev) => Math.max(prev - 1, 0));
350
+ } else if (event.key === 'Enter') {
351
+ event.preventDefault();
352
+ const action = flatActions[selectedIndex];
353
+ if (action) {
354
+ handleActionTrigger(action);
355
+ }
356
+ }
357
+ },
358
+ [flatActions, selectedIndex, handleActionTrigger]
359
+ );
360
+
361
+ // Reset selection on query change
362
+ const handleQueryChange = useCallback((value: string) => {
363
+ setQuery(value);
364
+ setSelectedIndex(0);
365
+ }, []);
366
+
367
+ return (
368
+ <Modal
369
+ opened={opened}
370
+ onClose={() => setOpened(false)}
371
+ withCloseButton={false}
372
+ padding={0}
373
+ size="lg"
374
+ radius="md"
375
+ centered
376
+ overlayProps={{ backgroundOpacity: 0.5, blur: 3 }}
377
+ >
378
+ <Box p="sm" onKeyDown={handleKeyDown}>
379
+ <TextInput
380
+ placeholder={searchPlaceholder}
381
+ value={query}
382
+ onChange={(e) => handleQueryChange(e.target.value)}
383
+ leftSection={<IconSearch size={18} />}
384
+ rightSection={loading ? <Loader size="xs" /> : null}
385
+ size="md"
386
+ autoFocus
387
+ data-autofocus
388
+ />
389
+ </Box>
390
+
391
+ <Divider />
392
+
393
+ <ScrollArea.Autosize mah={400} type="scroll">
394
+ <Box p="xs">
395
+ {flatActions.length === 0 ? (
396
+ <Center py="xl">
397
+ <Text c="dimmed" size="sm">
398
+ {nothingFoundMessage}
399
+ </Text>
400
+ </Center>
401
+ ) : (
402
+ <Stack gap={4}>
403
+ {Object.entries(groupedActions).map(([group, groupActionsList]) => (
404
+ <Box key={group}>
405
+ {group && groupActions && (
406
+ <Text size="xs" fw={500} c="dimmed" px="xs" py={4}>
407
+ {group}
408
+ </Text>
409
+ )}
410
+ {groupActionsList.map((action) => {
411
+ const globalIndex = flatActions.findIndex((a) => a.id === action.id);
412
+ return (
413
+ <ActionItem
414
+ key={action.id}
415
+ action={action}
416
+ query={query}
417
+ isSelected={globalIndex === selectedIndex}
418
+ highlightQuery={highlightQuery}
419
+ onClick={() => handleActionTrigger(action)}
420
+ />
421
+ );
422
+ })}
423
+ </Box>
424
+ ))}
425
+ </Stack>
426
+ )}
427
+ </Box>
428
+ </ScrollArea.Autosize>
429
+
430
+ <Divider />
431
+
432
+ <Group justify="space-between" p="xs">
433
+ <Group gap="xs">
434
+ <Kbd size="xs">↑↓</Kbd>
435
+ <Text size="xs" c="dimmed">
436
+ navegar
437
+ </Text>
438
+ </Group>
439
+ <Group gap="xs">
440
+ <Kbd size="xs">Enter</Kbd>
441
+ <Text size="xs" c="dimmed">
442
+ selecionar
443
+ </Text>
444
+ </Group>
445
+ <Group gap="xs">
446
+ <Kbd size="xs">Esc</Kbd>
447
+ <Text size="xs" c="dimmed">
448
+ fechar
449
+ </Text>
450
+ </Group>
451
+ </Group>
452
+ </Modal>
453
+ );
454
+ }
455
+
456
+ // =============================================================================
457
+ // Hook useArchbaseSpotlight
458
+ // =============================================================================
459
+
460
+ export interface UseArchbaseSpotlightOptions {
461
+ shortcut?: string;
462
+ }
463
+
464
+ export function useArchbaseSpotlight(options: UseArchbaseSpotlightOptions = {}) {
465
+ const { shortcut = 'mod+K' } = options;
466
+ const [opened, setOpened] = useState(false);
467
+
468
+ useHotkeys([[shortcut, () => setOpened(true)]]);
469
+
470
+ const open = useCallback(() => setOpened(true), []);
471
+ const close = useCallback(() => setOpened(false), []);
472
+ const toggle = useCallback(() => setOpened((prev) => !prev), []);
473
+
474
+ return {
475
+ opened,
476
+ open,
477
+ close,
478
+ toggle,
479
+ setOpened,
480
+ };
481
+ }
482
+
483
+ export default ArchbaseSpotlight;
@@ -1,4 +1,51 @@
1
1
  // Navigation Components - TODO: Implement
2
2
  export { NavLink as ArchbaseNavLink } from '@mantine/core';
3
3
  export { Breadcrumbs as ArchbaseBreadcrumbs } from '@mantine/core';
4
- export { Pagination as ArchbasePagination } from '@mantine/core';
4
+ export { Pagination as ArchbasePagination } from '@mantine/core';
5
+
6
+ export { ArchbaseContextMenu, useArchbaseContextMenu } from './ArchbaseContextMenu';
7
+ export type {
8
+ ArchbaseContextMenuProps,
9
+ ArchbaseContextMenuItem,
10
+ UseArchbaseContextMenuOptions,
11
+ UseArchbaseContextMenuReturn,
12
+ } from './ArchbaseContextMenu';
13
+
14
+ export { ArchbaseActionSheet, useArchbaseActionSheet } from './ArchbaseActionSheet';
15
+ export type {
16
+ ArchbaseActionSheetProps,
17
+ ArchbaseActionSheetItem,
18
+ UseArchbaseActionSheetOptions,
19
+ UseArchbaseActionSheetReturn,
20
+ } from './ArchbaseActionSheet';
21
+
22
+ export { ArchbaseBottomNavigation } from './ArchbaseBottomNavigation';
23
+ export type { ArchbaseBottomNavigationProps, ArchbaseBottomNavigationItem } from './ArchbaseBottomNavigation';
24
+
25
+ export { ArchbaseAppBar } from './ArchbaseAppBar';
26
+ export type { ArchbaseAppBarProps, ArchbaseAppBarAction } from './ArchbaseAppBar';
27
+
28
+ export { ArchbaseSpotlight, useArchbaseSpotlight } from './ArchbaseSpotlight';
29
+ export type {
30
+ ArchbaseSpotlightProps,
31
+ SpotlightAction,
32
+ UseArchbaseSpotlightOptions,
33
+ } from './ArchbaseSpotlight';
34
+
35
+ export {
36
+ ArchbaseKeyboardShortcutsProvider,
37
+ ArchbaseKeyboardShortcutsModal,
38
+ ArchbaseShortcutHint,
39
+ useArchbaseKeyboardShortcuts,
40
+ useArchbaseRegisterShortcut,
41
+ useArchbaseShortcutScope,
42
+ } from './ArchbaseKeyboardShortcuts';
43
+ export type {
44
+ KeyboardShortcut,
45
+ ArchbaseKeyboardShortcutsContextValue,
46
+ ArchbaseKeyboardShortcutsProviderProps,
47
+ ArchbaseKeyboardShortcutsModalProps,
48
+ UseArchbaseRegisterShortcutOptions,
49
+ UseArchbaseShortcutScopeReturn,
50
+ ArchbaseShortcutHintProps,
51
+ } from './ArchbaseKeyboardShortcuts';