@archbase/components 3.0.25 → 4.0.0

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
@@ -26,6 +26,9 @@ export { ArchbaseChipItem } from './ArchbaseChipItem';
26
26
  export type { ArchbaseColorPickerProps } from './ArchbaseColorPicker';
27
27
  export { ArchbaseColorPicker } from './ArchbaseColorPicker';
28
28
 
29
+ export { ArchbaseDualListbox } from './ArchbaseDualListbox';
30
+ export type { ArchbaseDualListboxProps, ArchbaseDualListboxOption } from './ArchbaseDualListbox';
31
+
29
32
  export type { ArchbaseDatePickerRangeProps } from './ArchbaseDatePickerRange';
30
33
  export { ArchbaseDatePickerRange } from './ArchbaseDatePickerRange';
31
34
 
@@ -119,3 +122,92 @@ export type { ArchbaseTimeEditProps } from './ArchbaseTimeEdit'
119
122
  export { ArchbaseAvatarEdit } from './ArchbaseAvatarEdit'
120
123
 
121
124
  export type { ArchbaseAvatarEditProps } from './ArchbaseAvatarEdit'
125
+
126
+ export { ArchbaseTagInput } from './ArchbaseTagInput'
127
+ export type { ArchbaseTagInputProps } from './ArchbaseTagInput'
128
+
129
+ export { ArchbasePhoneInput } from './ArchbasePhoneInput'
130
+ export type { ArchbasePhoneInputProps } from './ArchbasePhoneInput'
131
+
132
+ export { ArchbaseMultiEmail } from './ArchbaseMultiEmail'
133
+ export type { ArchbaseMultiEmailProps } from './ArchbaseMultiEmail'
134
+
135
+ export { ArchbaseMentionInput } from './ArchbaseMentionInput'
136
+ export type { ArchbaseMentionInputProps, ArchbaseMentionConfig } from './ArchbaseMentionInput'
137
+
138
+ export { ArchbaseSignaturePad } from './ArchbaseSignaturePad'
139
+ export type { ArchbaseSignaturePadProps } from './ArchbaseSignaturePad'
140
+
141
+ export { ArchbaseBarcodeScanner } from './ArchbaseBarcodeScanner'
142
+ export type { ArchbaseBarcodeScannerProps } from './ArchbaseBarcodeScanner'
143
+
144
+ export { ArchbaseSpreadsheet } from './ArchbaseSpreadsheet'
145
+ export type { ArchbaseSpreadsheetProps, ArchbaseColumnDef, ArchbaseColumnType } from './ArchbaseSpreadsheet'
146
+
147
+ export { ArchbaseLightGrid } from './ArchbaseLightGrid'
148
+ export type { ArchbaseLightGridProps, ArchbaseLightGridColumn } from './ArchbaseLightGrid'
149
+
150
+ export { ArchbaseCurrencyInput } from './ArchbaseCurrencyInput'
151
+ export type { ArchbaseCurrencyInputProps, CurrencyCode } from './ArchbaseCurrencyInput'
152
+
153
+ export { ArchbaseCpfCnpjInput, validateCPF, validateCNPJ, formatCPF, formatCNPJ, detectDocumentType } from './ArchbaseCpfCnpjInput'
154
+ export type { ArchbaseCpfCnpjInputProps, DocumentType } from './ArchbaseCpfCnpjInput'
155
+
156
+ export { ArchbaseCepInput, formatCep } from './ArchbaseCepInput'
157
+ export type { ArchbaseCepInputProps, CepAddress } from './ArchbaseCepInput'
158
+
159
+ export { ArchbaseOTPInput } from './ArchbaseOTPInput'
160
+ export type { ArchbaseOTPInputProps } from './ArchbaseOTPInput'
161
+
162
+ export { ArchbaseRangeSlider } from './ArchbaseRangeSlider'
163
+ export type { ArchbaseRangeSliderProps, RangeValue } from './ArchbaseRangeSlider'
164
+
165
+ export { ArchbaseInPlaceEditor } from './ArchbaseInPlaceEditor'
166
+ export type { ArchbaseInPlaceEditorProps, InPlaceEditorType, SelectOption } from './ArchbaseInPlaceEditor'
167
+
168
+ export { ArchbaseNumberStepper } from './ArchbaseNumberStepper'
169
+ export type { ArchbaseNumberStepperProps } from './ArchbaseNumberStepper'
170
+
171
+ export { ArchbaseAIPromptInput, useArchbasePromptHistory } from './ArchbaseAIPromptInput'
172
+ export type {
173
+ ArchbaseAIPromptInputProps,
174
+ ArchbaseAIPromptSuggestion,
175
+ UseArchbasePromptHistoryOptions,
176
+ UseArchbasePromptHistoryReturn,
177
+ } from './ArchbaseAIPromptInput'
178
+
179
+ export { ArchbaseColorGradientPicker, ArchbaseFlatColorPicker } from './ArchbaseColorGradientPicker'
180
+ export type {
181
+ ArchbaseColorGradientPickerProps,
182
+ ArchbaseFlatColorPickerProps,
183
+ ArchbaseColorFormat,
184
+ } from './ArchbaseColorGradientPicker'
185
+
186
+ export {
187
+ useArchbaseSpeechToText,
188
+ ArchbaseSpeechToTextButton,
189
+ ArchbaseSpeechToTextInput,
190
+ ArchbaseSpeechToTextArea,
191
+ } from './ArchbaseSpeechToTextInput'
192
+ export type {
193
+ UseArchbaseSpeechToTextOptions,
194
+ UseArchbaseSpeechToTextReturn,
195
+ ArchbaseSpeechToTextButtonProps,
196
+ ArchbaseSpeechToTextInputProps,
197
+ ArchbaseSpeechToTextAreaProps,
198
+ } from './ArchbaseSpeechToTextInput'
199
+
200
+ export {
201
+ ArchbaseMultiViewCalendar,
202
+ ArchbaseMultiViewCalendarWithPresets,
203
+ ArchbaseDateRangeQuickPicker,
204
+ defaultDatePresets,
205
+ createDatePreset,
206
+ } from './ArchbaseMultiViewCalendar'
207
+ export type {
208
+ ArchbaseMultiViewCalendarProps,
209
+ ArchbaseMultiViewCalendarWithPresetsProps,
210
+ ArchbaseDateRangeQuickPickerProps,
211
+ DateRangePreset,
212
+ } from './ArchbaseMultiViewCalendar'
213
+
@@ -0,0 +1,156 @@
1
+ import React, { forwardRef, useMemo } from 'react';
2
+ import { Progress, MantineColor, MantineSize, Box, Text, Stack } from '@mantine/core';
3
+
4
+ export interface ArchbaseChunkProgressBarProps {
5
+ /** Valor atual (0-100) */
6
+ value: number;
7
+ /** Quantidade de chunks */
8
+ chunkCount?: number;
9
+ /** Gap entre os chunks em pixels */
10
+ gap?: number;
11
+ /** Cor dos chunks incompletos */
12
+ color?: MantineColor;
13
+ /** Cor dos chunks completos */
14
+ completedColor?: MantineColor;
15
+ /** Se deve animar os chunks */
16
+ animated?: boolean;
17
+ /** Se deve ter listras */
18
+ striped?: boolean;
19
+ /** Tamanho da barra */
20
+ size?: MantineSize | number;
21
+ /** Raio da barra */
22
+ radius?: MantineSize | number;
23
+ /** Label opcional */
24
+ label?: string;
25
+ /** Se deve mostrar o percentual */
26
+ showPercentage?: boolean;
27
+ /** Formato do percentual */
28
+ percentageFormat?: (value: number) => string;
29
+ /** Largura */
30
+ width?: number | string;
31
+ /** Classe CSS */
32
+ className?: string;
33
+ /** Estilo */
34
+ style?: React.CSSProperties;
35
+ }
36
+
37
+ export const ArchbaseChunkProgressBar = forwardRef<HTMLDivElement, ArchbaseChunkProgressBarProps>(
38
+ (
39
+ {
40
+ value,
41
+ chunkCount = 10,
42
+ gap = 2,
43
+ color = 'gray.3',
44
+ completedColor = 'blue',
45
+ animated = false,
46
+ striped = false,
47
+ size = 'md',
48
+ radius = 'sm',
49
+ label,
50
+ showPercentage = false,
51
+ percentageFormat,
52
+ width,
53
+ className,
54
+ style,
55
+ },
56
+ ref
57
+ ) => {
58
+ // Calcula as seções do progress baseado no valor e chunks
59
+ const sections = useMemo(() => {
60
+ const clampedValue = Math.min(100, Math.max(0, value));
61
+ const chunkSize = 100 / chunkCount;
62
+ const completedChunks = Math.floor(clampedValue / chunkSize);
63
+ const partialChunk = (clampedValue % chunkSize) / chunkSize;
64
+
65
+ const result: Array<{ value: number; color: MantineColor }> = [];
66
+
67
+ // Chunks completos
68
+ for (let i = 0; i < completedChunks; i++) {
69
+ result.push({
70
+ value: chunkSize - (gap * (chunkCount - 1)) / chunkCount,
71
+ color: completedColor,
72
+ });
73
+ if (i < chunkCount - 1) {
74
+ result.push({
75
+ value: gap / chunkCount,
76
+ color: 'transparent' as MantineColor,
77
+ });
78
+ }
79
+ }
80
+
81
+ // Chunk parcial
82
+ if (completedChunks < chunkCount && partialChunk > 0) {
83
+ const partialValue = (chunkSize - (gap * (chunkCount - 1)) / chunkCount) * partialChunk;
84
+ result.push({
85
+ value: partialValue,
86
+ color: completedColor,
87
+ });
88
+ result.push({
89
+ value: chunkSize - partialValue - (gap * (chunkCount - 1)) / chunkCount,
90
+ color: color,
91
+ });
92
+ if (completedChunks < chunkCount - 1) {
93
+ result.push({
94
+ value: gap / chunkCount,
95
+ color: 'transparent' as MantineColor,
96
+ });
97
+ }
98
+ }
99
+
100
+ // Chunks restantes vazios
101
+ for (let i = completedChunks + (partialChunk > 0 ? 1 : 0); i < chunkCount; i++) {
102
+ result.push({
103
+ value: chunkSize - (gap * (chunkCount - 1)) / chunkCount,
104
+ color: color,
105
+ });
106
+ if (i < chunkCount - 1) {
107
+ result.push({
108
+ value: gap / chunkCount,
109
+ color: 'transparent' as MantineColor,
110
+ });
111
+ }
112
+ }
113
+
114
+ return result;
115
+ }, [chunkCount, color, completedColor, gap, value]);
116
+
117
+ // Formato do percentual
118
+ const formattedPercentage = useMemo(() => {
119
+ const clampedValue = Math.min(100, Math.max(0, value));
120
+ if (percentageFormat) return percentageFormat(clampedValue);
121
+ return `${Math.round(clampedValue)}%`;
122
+ }, [percentageFormat, value]);
123
+
124
+ return (
125
+ <Stack ref={ref} gap={4} className={className} style={{ ...style, width }}>
126
+ {(label || showPercentage) && (
127
+ <Box style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
128
+ {label && (
129
+ <Text size="sm" fw={500}>
130
+ {label}
131
+ </Text>
132
+ )}
133
+ {showPercentage && (
134
+ <Text size="sm" c="dimmed">
135
+ {formattedPercentage}
136
+ </Text>
137
+ )}
138
+ </Box>
139
+ )}
140
+ <Progress.Root size={size} radius={radius}>
141
+ {sections.map((section, index) => (
142
+ <Progress.Section
143
+ key={index}
144
+ value={section.value}
145
+ color={section.color}
146
+ animated={animated && section.color === completedColor}
147
+ striped={striped && section.color === completedColor}
148
+ />
149
+ ))}
150
+ </Progress.Root>
151
+ </Stack>
152
+ );
153
+ }
154
+ );
155
+
156
+ ArchbaseChunkProgressBar.displayName = 'ArchbaseChunkProgressBar';
@@ -0,0 +1,278 @@
1
+ import React, { forwardRef, useCallback, useState, ReactNode, MouseEvent, CSSProperties } from 'react';
2
+ import { Box, MantineColor } from '@mantine/core';
3
+
4
+ interface RippleItem {
5
+ id: number;
6
+ x: number;
7
+ y: number;
8
+ size: number;
9
+ }
10
+
11
+ export interface ArchbaseRippleProps {
12
+ /** Conteúdo a ser envolvido */
13
+ children: ReactNode;
14
+ /** Cor do ripple */
15
+ color?: MantineColor;
16
+ /** Opacidade do ripple */
17
+ opacity?: number;
18
+ /** Duração da animação em ms */
19
+ duration?: number;
20
+ /** Se o ripple deve ser centralizado */
21
+ centered?: boolean;
22
+ /** Se está desabilitado */
23
+ disabled?: boolean;
24
+ /** Se deve cobrir todo o elemento */
25
+ unbounded?: boolean;
26
+ /** Classe CSS */
27
+ className?: string;
28
+ /** Estilo */
29
+ style?: CSSProperties;
30
+ }
31
+
32
+ export const ArchbaseRipple = forwardRef<HTMLDivElement, ArchbaseRippleProps>(
33
+ (
34
+ {
35
+ children,
36
+ color = 'blue',
37
+ opacity = 0.3,
38
+ duration = 600,
39
+ centered = false,
40
+ disabled = false,
41
+ unbounded = false,
42
+ className,
43
+ style,
44
+ },
45
+ ref
46
+ ) => {
47
+ const [ripples, setRipples] = useState<RippleItem[]>([]);
48
+ const [nextId, setNextId] = useState(0);
49
+
50
+ const handleClick = useCallback(
51
+ (event: MouseEvent<HTMLDivElement>) => {
52
+ if (disabled) return;
53
+
54
+ const element = event.currentTarget;
55
+ const rect = element.getBoundingClientRect();
56
+
57
+ let x: number;
58
+ let y: number;
59
+ let size: number;
60
+
61
+ if (centered) {
62
+ x = rect.width / 2;
63
+ y = rect.height / 2;
64
+ size = Math.max(rect.width, rect.height);
65
+ } else {
66
+ x = event.clientX - rect.left;
67
+ y = event.clientY - rect.top;
68
+ // Calcula o tamanho para cobrir todo o elemento
69
+ const dx = Math.max(x, rect.width - x);
70
+ const dy = Math.max(y, rect.height - y);
71
+ size = Math.sqrt(dx * dx + dy * dy) * 2;
72
+ }
73
+
74
+ const newRipple: RippleItem = {
75
+ id: nextId,
76
+ x,
77
+ y,
78
+ size,
79
+ };
80
+
81
+ setRipples((prev) => [...prev, newRipple]);
82
+ setNextId((prev) => prev + 1);
83
+
84
+ // Remove o ripple após a animação
85
+ setTimeout(() => {
86
+ setRipples((prev) => prev.filter((r) => r.id !== newRipple.id));
87
+ }, duration);
88
+ },
89
+ [centered, disabled, duration, nextId]
90
+ );
91
+
92
+ const rippleColor = color.includes('.')
93
+ ? `var(--mantine-color-${color})`
94
+ : `var(--mantine-color-${color}-4)`;
95
+
96
+ return (
97
+ <Box
98
+ ref={ref}
99
+ className={className}
100
+ style={{
101
+ ...style,
102
+ position: 'relative',
103
+ overflow: unbounded ? 'visible' : 'hidden',
104
+ cursor: disabled ? 'default' : 'pointer',
105
+ }}
106
+ onClick={handleClick}
107
+ >
108
+ {children}
109
+
110
+ {/* Ripples container */}
111
+ <Box
112
+ style={{
113
+ position: 'absolute',
114
+ inset: 0,
115
+ pointerEvents: 'none',
116
+ overflow: unbounded ? 'visible' : 'hidden',
117
+ }}
118
+ >
119
+ {ripples.map((ripple) => (
120
+ <span
121
+ key={ripple.id}
122
+ style={{
123
+ position: 'absolute',
124
+ left: ripple.x - ripple.size / 2,
125
+ top: ripple.y - ripple.size / 2,
126
+ width: ripple.size,
127
+ height: ripple.size,
128
+ borderRadius: '50%',
129
+ backgroundColor: rippleColor,
130
+ opacity: opacity,
131
+ transform: 'scale(0)',
132
+ animation: `archbase-ripple ${duration}ms ease-out forwards`,
133
+ pointerEvents: 'none',
134
+ }}
135
+ />
136
+ ))}
137
+ </Box>
138
+
139
+ {/* Keyframes injection */}
140
+ <style>
141
+ {`
142
+ @keyframes archbase-ripple {
143
+ 0% {
144
+ transform: scale(0);
145
+ opacity: ${opacity};
146
+ }
147
+ 100% {
148
+ transform: scale(1);
149
+ opacity: 0;
150
+ }
151
+ }
152
+ `}
153
+ </style>
154
+ </Box>
155
+ );
156
+ }
157
+ );
158
+
159
+ ArchbaseRipple.displayName = 'ArchbaseRipple';
160
+
161
+ // ================== Hook para uso em componentes customizados ==================
162
+
163
+ export interface UseArchbaseRippleOptions {
164
+ color?: MantineColor;
165
+ opacity?: number;
166
+ duration?: number;
167
+ centered?: boolean;
168
+ disabled?: boolean;
169
+ }
170
+
171
+ export interface UseArchbaseRippleReturn {
172
+ ripples: RippleItem[];
173
+ handleClick: (event: MouseEvent<HTMLElement>) => void;
174
+ RippleContainer: React.FC;
175
+ }
176
+
177
+ export function useArchbaseRipple(options: UseArchbaseRippleOptions = {}): UseArchbaseRippleReturn {
178
+ const {
179
+ color = 'blue',
180
+ opacity = 0.3,
181
+ duration = 600,
182
+ centered = false,
183
+ disabled = false,
184
+ } = options;
185
+
186
+ const [ripples, setRipples] = useState<RippleItem[]>([]);
187
+ const [nextId, setNextId] = useState(0);
188
+
189
+ const handleClick = useCallback(
190
+ (event: MouseEvent<HTMLElement>) => {
191
+ if (disabled) return;
192
+
193
+ const element = event.currentTarget;
194
+ const rect = element.getBoundingClientRect();
195
+
196
+ let x: number;
197
+ let y: number;
198
+ let size: number;
199
+
200
+ if (centered) {
201
+ x = rect.width / 2;
202
+ y = rect.height / 2;
203
+ size = Math.max(rect.width, rect.height);
204
+ } else {
205
+ x = event.clientX - rect.left;
206
+ y = event.clientY - rect.top;
207
+ const dx = Math.max(x, rect.width - x);
208
+ const dy = Math.max(y, rect.height - y);
209
+ size = Math.sqrt(dx * dx + dy * dy) * 2;
210
+ }
211
+
212
+ const newRipple: RippleItem = {
213
+ id: nextId,
214
+ x,
215
+ y,
216
+ size,
217
+ };
218
+
219
+ setRipples((prev) => [...prev, newRipple]);
220
+ setNextId((prev) => prev + 1);
221
+
222
+ setTimeout(() => {
223
+ setRipples((prev) => prev.filter((r) => r.id !== newRipple.id));
224
+ }, duration);
225
+ },
226
+ [centered, disabled, duration, nextId]
227
+ );
228
+
229
+ const rippleColor = color.includes('.')
230
+ ? `var(--mantine-color-${color})`
231
+ : `var(--mantine-color-${color}-4)`;
232
+
233
+ const RippleContainer: React.FC = useCallback(
234
+ () => (
235
+ <>
236
+ {ripples.map((ripple) => (
237
+ <span
238
+ key={ripple.id}
239
+ style={{
240
+ position: 'absolute',
241
+ left: ripple.x - ripple.size / 2,
242
+ top: ripple.y - ripple.size / 2,
243
+ width: ripple.size,
244
+ height: ripple.size,
245
+ borderRadius: '50%',
246
+ backgroundColor: rippleColor,
247
+ opacity: opacity,
248
+ transform: 'scale(0)',
249
+ animation: `archbase-ripple ${duration}ms ease-out forwards`,
250
+ pointerEvents: 'none',
251
+ }}
252
+ />
253
+ ))}
254
+ <style>
255
+ {`
256
+ @keyframes archbase-ripple {
257
+ 0% {
258
+ transform: scale(0);
259
+ opacity: ${opacity};
260
+ }
261
+ 100% {
262
+ transform: scale(1);
263
+ opacity: 0;
264
+ }
265
+ }
266
+ `}
267
+ </style>
268
+ </>
269
+ ),
270
+ [duration, opacity, rippleColor, ripples]
271
+ );
272
+
273
+ return {
274
+ ripples,
275
+ handleClick,
276
+ RippleContainer,
277
+ };
278
+ }