@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,279 @@
1
+ import React, { useCallback, useState, createContext, useContext, ReactNode } from 'react';
2
+ import Lightbox, {
3
+ Slide,
4
+ SlideImage,
5
+ ControllerRef,
6
+ LightboxExternalProps,
7
+ } from 'yet-another-react-lightbox';
8
+ import Zoom from 'yet-another-react-lightbox/plugins/zoom';
9
+ import Thumbnails from 'yet-another-react-lightbox/plugins/thumbnails';
10
+ import Slideshow from 'yet-another-react-lightbox/plugins/slideshow';
11
+ import Fullscreen from 'yet-another-react-lightbox/plugins/fullscreen';
12
+ import Download from 'yet-another-react-lightbox/plugins/download';
13
+ import Counter from 'yet-another-react-lightbox/plugins/counter';
14
+ import Captions from 'yet-another-react-lightbox/plugins/captions';
15
+
16
+ // Import CSS
17
+ import 'yet-another-react-lightbox/styles.css';
18
+ import 'yet-another-react-lightbox/plugins/thumbnails.css';
19
+ import 'yet-another-react-lightbox/plugins/counter.css';
20
+ import 'yet-another-react-lightbox/plugins/captions.css';
21
+
22
+ // =============================================================================
23
+ // Types
24
+ // =============================================================================
25
+
26
+ export interface ArchbaseLightboxSlide {
27
+ /** URL da imagem */
28
+ src: string;
29
+ /** Título da imagem */
30
+ title?: string;
31
+ /** Descrição da imagem */
32
+ description?: string;
33
+ /** Texto alternativo */
34
+ alt?: string;
35
+ /** Largura da imagem (para otimização) */
36
+ width?: number;
37
+ /** Altura da imagem (para otimização) */
38
+ height?: number;
39
+ /** URL para download (se diferente de src) */
40
+ downloadUrl?: string;
41
+ /** Nome do arquivo para download */
42
+ downloadFilename?: string;
43
+ }
44
+
45
+ export interface ArchbaseLightboxProps extends Omit<LightboxExternalProps, 'slides' | 'open' | 'close'> {
46
+ /** Array de slides/imagens */
47
+ slides: ArchbaseLightboxSlide[];
48
+ /** Índice inicial do slide */
49
+ index?: number;
50
+ /** Se o lightbox está aberto */
51
+ open: boolean;
52
+ /** Callback ao fechar */
53
+ onClose: () => void;
54
+ /** Habilita zoom */
55
+ enableZoom?: boolean;
56
+ /** Habilita thumbnails */
57
+ enableThumbnails?: boolean;
58
+ /** Habilita slideshow */
59
+ enableSlideshow?: boolean;
60
+ /** Habilita fullscreen */
61
+ enableFullscreen?: boolean;
62
+ /** Habilita download */
63
+ enableDownload?: boolean;
64
+ /** Mostra contador */
65
+ showCounter?: boolean;
66
+ /** Mostra captions (título/descrição) */
67
+ showCaptions?: boolean;
68
+ /** Intervalo do slideshow em ms */
69
+ slideshowDelay?: number;
70
+ /** Nível máximo de zoom */
71
+ maxZoomPixelRatio?: number;
72
+ /** Callback ao mudar de slide */
73
+ onSlideChange?: (index: number) => void;
74
+ }
75
+
76
+ // =============================================================================
77
+ // Hook useArchbaseLightbox
78
+ // =============================================================================
79
+
80
+ export interface UseArchbaseLightboxReturn {
81
+ /** Se o lightbox está aberto */
82
+ isOpen: boolean;
83
+ /** Índice atual */
84
+ currentIndex: number;
85
+ /** Slides configurados */
86
+ slides: ArchbaseLightboxSlide[];
87
+ /** Abre o lightbox */
88
+ open: (slides: ArchbaseLightboxSlide[], index?: number) => void;
89
+ /** Fecha o lightbox */
90
+ close: () => void;
91
+ /** Vai para um slide específico */
92
+ goTo: (index: number) => void;
93
+ /** Props para passar ao componente */
94
+ lightboxProps: {
95
+ slides: ArchbaseLightboxSlide[];
96
+ index: number;
97
+ open: boolean;
98
+ onClose: () => void;
99
+ onSlideChange: (index: number) => void;
100
+ };
101
+ }
102
+
103
+ export function useArchbaseLightbox(): UseArchbaseLightboxReturn {
104
+ const [isOpen, setIsOpen] = useState(false);
105
+ const [currentIndex, setCurrentIndex] = useState(0);
106
+ const [slides, setSlides] = useState<ArchbaseLightboxSlide[]>([]);
107
+
108
+ const open = useCallback((newSlides: ArchbaseLightboxSlide[], index = 0) => {
109
+ setSlides(newSlides);
110
+ setCurrentIndex(index);
111
+ setIsOpen(true);
112
+ }, []);
113
+
114
+ const close = useCallback(() => {
115
+ setIsOpen(false);
116
+ }, []);
117
+
118
+ const goTo = useCallback((index: number) => {
119
+ setCurrentIndex(index);
120
+ }, []);
121
+
122
+ return {
123
+ isOpen,
124
+ currentIndex,
125
+ slides,
126
+ open,
127
+ close,
128
+ goTo,
129
+ lightboxProps: {
130
+ slides,
131
+ index: currentIndex,
132
+ open: isOpen,
133
+ onClose: close,
134
+ onSlideChange: setCurrentIndex,
135
+ },
136
+ };
137
+ }
138
+
139
+ // =============================================================================
140
+ // Context
141
+ // =============================================================================
142
+
143
+ interface LightboxContextType {
144
+ open: (slides: ArchbaseLightboxSlide[], index?: number) => void;
145
+ close: () => void;
146
+ }
147
+
148
+ const LightboxContext = createContext<LightboxContextType | null>(null);
149
+
150
+ export function useArchbaseLightboxContext(): LightboxContextType {
151
+ const context = useContext(LightboxContext);
152
+ if (!context) {
153
+ throw new Error('useArchbaseLightboxContext must be used within ArchbaseLightboxProvider');
154
+ }
155
+ return context;
156
+ }
157
+
158
+ // =============================================================================
159
+ // Provider
160
+ // =============================================================================
161
+
162
+ export interface ArchbaseLightboxProviderProps {
163
+ children: ReactNode;
164
+ /** Props padrão para o lightbox */
165
+ defaultProps?: Partial<ArchbaseLightboxProps>;
166
+ }
167
+
168
+ export function ArchbaseLightboxProvider({ children, defaultProps }: ArchbaseLightboxProviderProps) {
169
+ const lightbox = useArchbaseLightbox();
170
+
171
+ return (
172
+ <LightboxContext.Provider value={{ open: lightbox.open, close: lightbox.close }}>
173
+ {children}
174
+ <ArchbaseLightbox {...defaultProps} {...lightbox.lightboxProps} />
175
+ </LightboxContext.Provider>
176
+ );
177
+ }
178
+
179
+ // =============================================================================
180
+ // Component
181
+ // =============================================================================
182
+
183
+ export function ArchbaseLightbox({
184
+ slides,
185
+ index = 0,
186
+ open,
187
+ onClose,
188
+ enableZoom = true,
189
+ enableThumbnails = true,
190
+ enableSlideshow = false,
191
+ enableFullscreen = true,
192
+ enableDownload = false,
193
+ showCounter = true,
194
+ showCaptions = true,
195
+ slideshowDelay = 3000,
196
+ maxZoomPixelRatio = 4,
197
+ onSlideChange,
198
+ ...rest
199
+ }: ArchbaseLightboxProps) {
200
+ // Converte slides para o formato do lightbox
201
+ const lightboxSlides: Slide[] = slides.map((slide) => ({
202
+ src: slide.src,
203
+ alt: slide.alt,
204
+ width: slide.width,
205
+ height: slide.height,
206
+ title: slide.title,
207
+ description: slide.description,
208
+ download: slide.downloadUrl
209
+ ? { url: slide.downloadUrl, filename: slide.downloadFilename }
210
+ : undefined,
211
+ }));
212
+
213
+ // Configura plugins baseado nas props
214
+ const plugins = [];
215
+ if (enableZoom) plugins.push(Zoom);
216
+ if (enableThumbnails) plugins.push(Thumbnails);
217
+ if (enableSlideshow) plugins.push(Slideshow);
218
+ if (enableFullscreen) plugins.push(Fullscreen);
219
+ if (enableDownload) plugins.push(Download);
220
+ if (showCounter) plugins.push(Counter);
221
+ if (showCaptions) plugins.push(Captions);
222
+
223
+ const handleViewChange = useCallback(
224
+ ({ index: newIndex }: { index: number }) => {
225
+ onSlideChange?.(newIndex);
226
+ },
227
+ [onSlideChange]
228
+ );
229
+
230
+ return (
231
+ <Lightbox
232
+ open={open}
233
+ close={onClose}
234
+ index={index}
235
+ slides={lightboxSlides}
236
+ plugins={plugins}
237
+ on={{ view: handleViewChange }}
238
+ zoom={{
239
+ maxZoomPixelRatio,
240
+ scrollToZoom: true,
241
+ }}
242
+ slideshow={{
243
+ delay: slideshowDelay,
244
+ autoplay: false,
245
+ }}
246
+ thumbnails={{
247
+ position: 'bottom',
248
+ width: 120,
249
+ height: 80,
250
+ border: 2,
251
+ borderRadius: 4,
252
+ padding: 4,
253
+ gap: 8,
254
+ }}
255
+ carousel={{
256
+ finite: false,
257
+ preload: 2,
258
+ padding: '16px',
259
+ }}
260
+ animation={{
261
+ fade: 250,
262
+ swipe: 250,
263
+ }}
264
+ controller={{
265
+ closeOnPullDown: true,
266
+ closeOnBackdropClick: true,
267
+ }}
268
+ {...rest}
269
+ />
270
+ );
271
+ }
272
+
273
+ ArchbaseLightbox.displayName = 'ArchbaseLightbox';
274
+
275
+ // =============================================================================
276
+ // Exports
277
+ // =============================================================================
278
+
279
+ export default ArchbaseLightbox;
@@ -0,0 +1,268 @@
1
+ import React, { ReactNode, CSSProperties, useRef, useEffect, useState } from 'react';
2
+ import { Box, BoxProps, useMantineTheme } from '@mantine/core';
3
+
4
+ // =============================================================================
5
+ // Types
6
+ // =============================================================================
7
+
8
+ export type MarqueeDirection = 'left' | 'right' | 'up' | 'down';
9
+
10
+ export interface ArchbaseMarqueeProps extends Omit<BoxProps, 'children'> {
11
+ /** Conteúdo a ser animado */
12
+ children: ReactNode;
13
+ /** Direção do movimento */
14
+ direction?: MarqueeDirection;
15
+ /** Velocidade em pixels por segundo */
16
+ speed?: number;
17
+ /** Pausar ao passar o mouse */
18
+ pauseOnHover?: boolean;
19
+ /** Pausar ao clicar */
20
+ pauseOnClick?: boolean;
21
+ /** Número de cópias do conteúdo (para loop contínuo) */
22
+ copies?: number;
23
+ /** Gap entre as cópias */
24
+ gap?: number;
25
+ /** Gradient fade nas bordas */
26
+ gradient?: boolean;
27
+ /** Largura do gradient em pixels */
28
+ gradientWidth?: number;
29
+ /** Cor do gradient (background) */
30
+ gradientColor?: string;
31
+ /** Desabilitar animação */
32
+ disabled?: boolean;
33
+ /** Delay antes de iniciar (ms) */
34
+ delay?: number;
35
+ }
36
+
37
+ // =============================================================================
38
+ // Keyframes CSS
39
+ // =============================================================================
40
+
41
+ const getKeyframes = (direction: MarqueeDirection, distance: number): string => {
42
+ const name = `marquee-${direction}-${Math.abs(distance)}`;
43
+
44
+ switch (direction) {
45
+ case 'left':
46
+ return `
47
+ @keyframes ${name} {
48
+ from { transform: translateX(0); }
49
+ to { transform: translateX(-${distance}px); }
50
+ }
51
+ `;
52
+ case 'right':
53
+ return `
54
+ @keyframes ${name} {
55
+ from { transform: translateX(-${distance}px); }
56
+ to { transform: translateX(0); }
57
+ }
58
+ `;
59
+ case 'up':
60
+ return `
61
+ @keyframes ${name} {
62
+ from { transform: translateY(0); }
63
+ to { transform: translateY(-${distance}px); }
64
+ }
65
+ `;
66
+ case 'down':
67
+ return `
68
+ @keyframes ${name} {
69
+ from { transform: translateY(-${distance}px); }
70
+ to { transform: translateY(0); }
71
+ }
72
+ `;
73
+ }
74
+ };
75
+
76
+ // =============================================================================
77
+ // ArchbaseMarquee Component
78
+ // =============================================================================
79
+
80
+ export function ArchbaseMarquee({
81
+ children,
82
+ direction = 'left',
83
+ speed = 50,
84
+ pauseOnHover = true,
85
+ pauseOnClick = false,
86
+ copies = 2,
87
+ gap = 40,
88
+ gradient = true,
89
+ gradientWidth = 50,
90
+ gradientColor,
91
+ disabled = false,
92
+ delay = 0,
93
+ ...boxProps
94
+ }: ArchbaseMarqueeProps) {
95
+ const theme = useMantineTheme();
96
+ const containerRef = useRef<HTMLDivElement>(null);
97
+ const contentRef = useRef<HTMLDivElement>(null);
98
+ const [contentSize, setContentSize] = useState(0);
99
+ const [isPaused, setIsPaused] = useState(false);
100
+ const [isReady, setIsReady] = useState(false);
101
+
102
+ const isHorizontal = direction === 'left' || direction === 'right';
103
+
104
+ // Measure content size
105
+ useEffect(() => {
106
+ if (contentRef.current) {
107
+ const size = isHorizontal
108
+ ? contentRef.current.offsetWidth
109
+ : contentRef.current.offsetHeight;
110
+ setContentSize(size + gap);
111
+
112
+ // Add small delay before showing animation
113
+ const timer = setTimeout(() => setIsReady(true), delay);
114
+ return () => clearTimeout(timer);
115
+ }
116
+ }, [children, isHorizontal, gap, delay]);
117
+
118
+ // Calculate animation duration based on speed
119
+ const duration = contentSize / speed;
120
+
121
+ // Generate keyframes
122
+ const keyframeName = `marquee-${direction}-${contentSize}`;
123
+ const keyframesCss = contentSize > 0 ? getKeyframes(direction, contentSize) : '';
124
+
125
+ // Gradient styles
126
+ const bgColor = gradientColor ?? theme.colors.dark[7];
127
+ const gradientStyle: CSSProperties = gradient
128
+ ? {
129
+ maskImage: isHorizontal
130
+ ? `linear-gradient(to right, transparent, black ${gradientWidth}px, black calc(100% - ${gradientWidth}px), transparent)`
131
+ : `linear-gradient(to bottom, transparent, black ${gradientWidth}px, black calc(100% - ${gradientWidth}px), transparent)`,
132
+ WebkitMaskImage: isHorizontal
133
+ ? `linear-gradient(to right, transparent, black ${gradientWidth}px, black calc(100% - ${gradientWidth}px), transparent)`
134
+ : `linear-gradient(to bottom, transparent, black ${gradientWidth}px, black calc(100% - ${gradientWidth}px), transparent)`,
135
+ }
136
+ : {};
137
+
138
+ // Container styles
139
+ const containerStyle: CSSProperties = {
140
+ overflow: 'hidden',
141
+ ...gradientStyle,
142
+ };
143
+
144
+ // Track styles
145
+ const trackStyle: CSSProperties = {
146
+ display: 'flex',
147
+ flexDirection: isHorizontal ? 'row' : 'column',
148
+ gap: gap,
149
+ width: isHorizontal ? 'max-content' : '100%',
150
+ animation:
151
+ disabled || !isReady || contentSize === 0
152
+ ? 'none'
153
+ : `${keyframeName} ${duration}s linear infinite`,
154
+ animationPlayState: isPaused ? 'paused' : 'running',
155
+ };
156
+
157
+ // Event handlers
158
+ const handleMouseEnter = () => {
159
+ if (pauseOnHover) setIsPaused(true);
160
+ };
161
+
162
+ const handleMouseLeave = () => {
163
+ if (pauseOnHover) setIsPaused(false);
164
+ };
165
+
166
+ const handleClick = () => {
167
+ if (pauseOnClick) setIsPaused(!isPaused);
168
+ };
169
+
170
+ // Render copies
171
+ const renderCopies = () => {
172
+ const items = [];
173
+ for (let i = 0; i < copies; i++) {
174
+ items.push(
175
+ <Box key={i} ref={i === 0 ? contentRef : undefined}>
176
+ {children}
177
+ </Box>
178
+ );
179
+ }
180
+ return items;
181
+ };
182
+
183
+ return (
184
+ <>
185
+ {/* Inject keyframes */}
186
+ {keyframesCss && (
187
+ <style dangerouslySetInnerHTML={{ __html: keyframesCss }} />
188
+ )}
189
+
190
+ <Box
191
+ ref={containerRef}
192
+ style={containerStyle}
193
+ onMouseEnter={handleMouseEnter}
194
+ onMouseLeave={handleMouseLeave}
195
+ onClick={handleClick}
196
+ {...boxProps}
197
+ >
198
+ <Box style={trackStyle}>{renderCopies()}</Box>
199
+ </Box>
200
+ </>
201
+ );
202
+ }
203
+
204
+ // =============================================================================
205
+ // Convenience Components
206
+ // =============================================================================
207
+
208
+ /** Marquee horizontal da esquerda para direita */
209
+ export function ArchbaseMarqueeLeft(
210
+ props: Omit<ArchbaseMarqueeProps, 'direction'>
211
+ ) {
212
+ return <ArchbaseMarquee direction="left" {...props} />;
213
+ }
214
+
215
+ /** Marquee horizontal da direita para esquerda */
216
+ export function ArchbaseMarqueeRight(
217
+ props: Omit<ArchbaseMarqueeProps, 'direction'>
218
+ ) {
219
+ return <ArchbaseMarquee direction="right" {...props} />;
220
+ }
221
+
222
+ /** Marquee vertical de cima para baixo */
223
+ export function ArchbaseMarqueeUp(
224
+ props: Omit<ArchbaseMarqueeProps, 'direction'>
225
+ ) {
226
+ return <ArchbaseMarquee direction="up" {...props} />;
227
+ }
228
+
229
+ /** Marquee vertical de baixo para cima */
230
+ export function ArchbaseMarqueeDown(
231
+ props: Omit<ArchbaseMarqueeProps, 'direction'>
232
+ ) {
233
+ return <ArchbaseMarquee direction="down" {...props} />;
234
+ }
235
+
236
+ // =============================================================================
237
+ // ArchbaseTextTicker (ticker de notícias)
238
+ // =============================================================================
239
+
240
+ export interface ArchbaseTextTickerProps extends Omit<ArchbaseMarqueeProps, 'children'> {
241
+ /** Array de textos */
242
+ items: string[];
243
+ /** Separador entre itens */
244
+ separator?: ReactNode;
245
+ }
246
+
247
+ export function ArchbaseTextTicker({
248
+ items,
249
+ separator = ' • ',
250
+ ...props
251
+ }: ArchbaseTextTickerProps) {
252
+ return (
253
+ <ArchbaseMarquee {...props}>
254
+ <Box style={{ display: 'flex', alignItems: 'center', whiteSpace: 'nowrap' }}>
255
+ {items.map((item, index) => (
256
+ <React.Fragment key={index}>
257
+ <span>{item}</span>
258
+ {index < items.length - 1 && (
259
+ <span style={{ margin: '0 8px', opacity: 0.5 }}>{separator}</span>
260
+ )}
261
+ </React.Fragment>
262
+ ))}
263
+ </Box>
264
+ </ArchbaseMarquee>
265
+ );
266
+ }
267
+
268
+ export default ArchbaseMarquee;