@archbase/components 3.0.23 → 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
@@ -0,0 +1,133 @@
1
+ import React, { useCallback, useEffect, useState } from 'react';
2
+ import {
3
+ PinInput,
4
+ PinInputProps,
5
+ Stack,
6
+ Group,
7
+ Text,
8
+ Button,
9
+ Box,
10
+ } from '@mantine/core';
11
+ import { IconRefresh } from '@tabler/icons-react';
12
+
13
+ // =============================================================================
14
+ // Types
15
+ // =============================================================================
16
+
17
+ export interface ArchbaseOTPInputProps extends Omit<PinInputProps, 'value' | 'onChange' | 'error'> {
18
+ /** Número de dígitos (padrão: 6) */
19
+ length?: number;
20
+ /** Valor atual */
21
+ value?: string;
22
+ /** Callback ao mudar */
23
+ onChange?: (value: string) => void;
24
+ /** Callback ao completar */
25
+ onComplete?: (value: string) => void;
26
+ /** Mostrar botão de reenviar */
27
+ showResend?: boolean;
28
+ /** Callback ao reenviar */
29
+ onResend?: () => void;
30
+ /** Tempo de espera para reenviar (segundos) */
31
+ resendCooldown?: number;
32
+ /** Texto do botão reenviar */
33
+ resendText?: string;
34
+ /** Erro */
35
+ errorMessage?: string;
36
+ /** Máscara */
37
+ mask?: boolean;
38
+ }
39
+
40
+ // =============================================================================
41
+ // ArchbaseOTPInput Component
42
+ // =============================================================================
43
+
44
+ export function ArchbaseOTPInput({
45
+ length = 6,
46
+ value = '',
47
+ onChange,
48
+ onComplete,
49
+ showResend = false,
50
+ onResend,
51
+ resendCooldown = 60,
52
+ resendText = 'Reenviar código',
53
+ errorMessage,
54
+ mask = false,
55
+ ...props
56
+ }: ArchbaseOTPInputProps) {
57
+ const [countdown, setCountdown] = useState(0);
58
+
59
+ useEffect(() => {
60
+ if (countdown > 0) {
61
+ const timer = setTimeout(() => setCountdown(countdown - 1), 1000);
62
+ return () => clearTimeout(timer);
63
+ }
64
+ }, [countdown]);
65
+
66
+ const handleChange = useCallback(
67
+ (newValue: string) => {
68
+ onChange?.(newValue);
69
+ if (newValue.length === length) {
70
+ onComplete?.(newValue);
71
+ }
72
+ },
73
+ [onChange, onComplete, length]
74
+ );
75
+
76
+ const handleResend = useCallback(() => {
77
+ onResend?.();
78
+ setCountdown(resendCooldown);
79
+ }, [onResend, resendCooldown]);
80
+
81
+ return (
82
+ <Stack gap="sm" align="center">
83
+ <PinInput
84
+ {...props}
85
+ length={length}
86
+ value={value}
87
+ onChange={handleChange}
88
+ type={mask ? 'number' : 'number'}
89
+ mask={mask}
90
+ error={!!errorMessage}
91
+ />
92
+
93
+ {errorMessage && (
94
+ <Text size="sm" c="red">
95
+ {errorMessage}
96
+ </Text>
97
+ )}
98
+
99
+ {showResend && (
100
+ <Group gap="xs">
101
+ {countdown > 0 ? (
102
+ <Text size="sm" c="dimmed">
103
+ Reenviar em {countdown}s
104
+ </Text>
105
+ ) : (
106
+ <Button
107
+ variant="subtle"
108
+ size="xs"
109
+ leftSection={<IconRefresh size={14} />}
110
+ onClick={handleResend}
111
+ >
112
+ {resendText}
113
+ </Button>
114
+ )}
115
+ </Group>
116
+ )}
117
+ </Stack>
118
+ );
119
+ }
120
+
121
+ // =============================================================================
122
+ // Convenience Components
123
+ // =============================================================================
124
+
125
+ export function ArchbaseOTP4Input(props: Omit<ArchbaseOTPInputProps, 'length'>) {
126
+ return <ArchbaseOTPInput length={4} {...props} />;
127
+ }
128
+
129
+ export function ArchbaseOTP6Input(props: Omit<ArchbaseOTPInputProps, 'length'>) {
130
+ return <ArchbaseOTPInput length={6} {...props} />;
131
+ }
132
+
133
+ export default ArchbaseOTPInput;
@@ -185,7 +185,7 @@ export function ArchbaseOperatingHoursEditor({
185
185
  <Group justify='space-between'>
186
186
  <Group wrap='nowrap'>
187
187
  <Text fw={700} size={"12px"}>{oh.days.map((day) => daysOfWeekTranslate.find((d) => d.value === day)?.label || 'Dia desconhecido').join(',')}</Text>
188
- <Text size={"12px"} fw={700} color="blue">{oh.timeRange}</Text>
188
+ <Text size={"12px"} fw={700} c="blue">{oh.timeRange}</Text>
189
189
  </Group>
190
190
  <ActionIcon
191
191
  color="red"
@@ -0,0 +1,355 @@
1
+ /**
2
+ * ArchbasePhoneInput — input de telefone internacional integrado ao DataSource (v1/v2)
3
+ * com suporte a validação, estado controlado e seleção de país.
4
+ * @status stable
5
+ */
6
+ import { Input, MantineSize, useMantineColorScheme, useMantineTheme } from '@mantine/core';
7
+ import { useForceUpdate } from '@mantine/hooks';
8
+ import type { CSSProperties, FocusEventHandler } from 'react';
9
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
10
+ import PhoneInput from 'react-phone-number-input';
11
+ import 'react-phone-number-input/style.css';
12
+ import type { DataSourceEvent, IArchbaseDataSourceBase } from '@archbase/data';
13
+ import { DataSourceEventNames, useArchbaseDidUpdate, useArchbaseV1V2Compatibility } from '@archbase/data';
14
+ import { useValidationErrors } from '@archbase/core';
15
+ import type { CountryCode } from 'libphonenumber-js';
16
+
17
+ export interface ArchbasePhoneInputProps<T, ID> {
18
+ /** Fonte de dados onde será atribuído o valor do phone input (V1 ou V2) */
19
+ dataSource?: IArchbaseDataSourceBase<T>;
20
+ /** Campo onde deverá ser atribuído o valor do phone input na fonte de dados */
21
+ dataField?: string;
22
+ /** Valor controlado do phone input (modo standalone) */
23
+ value?: string;
24
+ /** Valor padrão do phone input (modo standalone) */
25
+ defaultValue?: string;
26
+ /** País padrão selecionado no seletor de bandeiras */
27
+ defaultCountry?: CountryCode;
28
+ /** Se true, exibe o número em formato internacional (+55 ...) */
29
+ international?: boolean;
30
+ /** Título/label do phone input */
31
+ label?: string;
32
+ /** Descrição exibida abaixo do label */
33
+ description?: string;
34
+ /** Mensagem de erro a ser exibida */
35
+ error?: string;
36
+ /** Texto de placeholder do phone input */
37
+ placeholder?: string;
38
+ /** Indicador se o preenchimento é obrigatório */
39
+ required?: boolean;
40
+ /** Indicador se o phone input está desabilitado */
41
+ disabled?: boolean;
42
+ /** Indicador se o phone input é somente leitura. Obs: usado em conjunto com o status da fonte de dados */
43
+ readOnly?: boolean;
44
+ /** Evento quando o valor do phone input é alterado */
45
+ onChangeValue?: (value: string | undefined) => void;
46
+ /** Evento quando o phone input recebe o foco */
47
+ onFocusEnter?: FocusEventHandler<HTMLInputElement> | undefined;
48
+ /** Evento quando o foco sai do phone input */
49
+ onFocusExit?: FocusEventHandler<HTMLInputElement> | undefined;
50
+ /** Referência para o componente interno */
51
+ innerRef?: React.RefObject<HTMLInputElement> | undefined;
52
+ /** Estilo CSS customizado aplicado ao wrapper */
53
+ style?: CSSProperties;
54
+ /** Classe CSS customizada aplicada ao wrapper */
55
+ className?: string;
56
+ /** Largura do componente */
57
+ width?: string | number;
58
+ /** Tamanho do componente seguindo o padrão Mantine */
59
+ size?: MantineSize;
60
+ }
61
+
62
+ export function ArchbasePhoneInput<T, ID>({
63
+ dataSource,
64
+ dataField,
65
+ value: valueProp,
66
+ defaultValue = '',
67
+ defaultCountry = 'BR',
68
+ international = true,
69
+ label,
70
+ description,
71
+ error,
72
+ placeholder,
73
+ required,
74
+ disabled = false,
75
+ readOnly = false,
76
+ onChangeValue,
77
+ onFocusEnter,
78
+ onFocusExit,
79
+ innerRef,
80
+ style,
81
+ className,
82
+ width,
83
+ size = 'sm',
84
+ }: ArchbasePhoneInputProps<T, ID>) {
85
+ // Hook de compatibilidade V1/V2
86
+ const v1v2Compatibility = useArchbaseV1V2Compatibility<string>(
87
+ 'ArchbasePhoneInput',
88
+ dataSource,
89
+ dataField,
90
+ '',
91
+ );
92
+
93
+ const innerComponentRef = innerRef || useRef<any>(null);
94
+ const [currentValue, setCurrentValue] = useState<string>(valueProp || defaultValue || '');
95
+ const forceUpdate = useForceUpdate();
96
+ const [internalError, setInternalError] = useState<string | undefined>(error);
97
+ const theme = useMantineTheme();
98
+ const { colorScheme } = useMantineColorScheme();
99
+
100
+ // Contexto de validação (opcional - pode não existir)
101
+ const validationContext = useValidationErrors();
102
+
103
+ // Chave única para o field
104
+ const fieldKey = `${dataField}`;
105
+
106
+ // Recuperar erro do contexto se existir
107
+ const contextError = validationContext?.getError(fieldKey);
108
+
109
+ // Detecta automaticamente se é DataSource V2
110
+ const isDataSourceV2 =
111
+ dataSource &&
112
+ ('appendToFieldArray' in dataSource || 'updateFieldArrayItem' in dataSource);
113
+
114
+ // Para V2: estado otimizado (sem re-renders desnecessários)
115
+ const [v2Value, setV2Value] = useState<string>('');
116
+
117
+ // Apenas atualizar se o prop error vier definido
118
+ useEffect(() => {
119
+ if (error !== undefined && error !== internalError) {
120
+ setInternalError(error);
121
+ }
122
+ }, [error]);
123
+
124
+ const loadDataSourceFieldValue = () => {
125
+ let initialValue: any = valueProp || defaultValue || '';
126
+
127
+ if (dataSource && dataField) {
128
+ initialValue = dataSource.getFieldValue(dataField);
129
+ if (!initialValue) {
130
+ initialValue = '';
131
+ }
132
+ }
133
+
134
+ if (isDataSourceV2) {
135
+ setV2Value(initialValue);
136
+ } else {
137
+ setCurrentValue(initialValue);
138
+ }
139
+ };
140
+
141
+ const fieldChangedListener = useCallback(() => {
142
+ loadDataSourceFieldValue();
143
+ }, []);
144
+
145
+ const dataSourceEvent = useCallback(
146
+ (event: DataSourceEvent<T>) => {
147
+ if (dataSource && dataField) {
148
+ if (
149
+ event.type === DataSourceEventNames.dataChanged ||
150
+ event.type === DataSourceEventNames.recordChanged ||
151
+ event.type === DataSourceEventNames.afterScroll ||
152
+ event.type === DataSourceEventNames.afterCancel ||
153
+ event.type === DataSourceEventNames.afterEdit
154
+ ) {
155
+ loadDataSourceFieldValue();
156
+ if (!isDataSourceV2) {
157
+ forceUpdate();
158
+ }
159
+ }
160
+
161
+ if (
162
+ event.type === DataSourceEventNames.onFieldError &&
163
+ event.fieldName === dataField
164
+ ) {
165
+ setInternalError(event.error);
166
+ validationContext?.setError(fieldKey, event.error);
167
+ if (!isDataSourceV2) {
168
+ forceUpdate();
169
+ }
170
+ }
171
+ }
172
+ },
173
+ [isDataSourceV2, dataSource, dataField, validationContext, fieldKey],
174
+ );
175
+
176
+ // Ref para manter callback sempre atualizado (corrige problema de closure desatualizada)
177
+ const dataSourceEventRef = useRef(dataSourceEvent);
178
+ useEffect(() => {
179
+ dataSourceEventRef.current = dataSourceEvent;
180
+ }, [dataSourceEvent]);
181
+
182
+ // Wrapper estável que delega para ref - nunca muda, então o listener permanece consistente
183
+ const stableDataSourceEvent = useCallback((event: DataSourceEvent<T>) => {
184
+ dataSourceEventRef.current(event);
185
+ }, []);
186
+
187
+ // Registrar listeners com cleanup apropriado
188
+ useEffect(() => {
189
+ loadDataSourceFieldValue();
190
+ if (dataSource && dataField) {
191
+ const hasFieldListener =
192
+ typeof (dataSource as any).addFieldChangeListener === 'function';
193
+ dataSource.addListener(stableDataSourceEvent);
194
+ if (hasFieldListener) {
195
+ (dataSource as any).addFieldChangeListener(dataField, fieldChangedListener);
196
+ }
197
+
198
+ return () => {
199
+ dataSource.removeListener(stableDataSourceEvent);
200
+ if (hasFieldListener) {
201
+ (dataSource as any).removeFieldChangeListener(dataField, fieldChangedListener);
202
+ }
203
+ };
204
+ }
205
+ }, [dataSource, dataField, stableDataSourceEvent, fieldChangedListener]);
206
+
207
+ useArchbaseDidUpdate(() => {
208
+ loadDataSourceFieldValue();
209
+ }, []);
210
+
211
+ const handleChange = (newValue: string | undefined) => {
212
+ const changedValue = newValue || '';
213
+
214
+ // Limpa erro quando usuário edita o campo
215
+ const hasError = internalError || contextError;
216
+ if (hasError) {
217
+ setInternalError(undefined);
218
+ validationContext?.clearError(fieldKey);
219
+ }
220
+
221
+ if (isDataSourceV2) {
222
+ setV2Value(changedValue);
223
+ if (
224
+ dataSource &&
225
+ !dataSource.isBrowsing() &&
226
+ dataField &&
227
+ dataSource.getFieldValue(dataField) !== changedValue
228
+ ) {
229
+ dataSource.setFieldValue(dataField, changedValue);
230
+ }
231
+ } else {
232
+ setCurrentValue(changedValue);
233
+ if (
234
+ dataSource &&
235
+ !dataSource.isBrowsing() &&
236
+ dataField &&
237
+ dataSource.getFieldValue(dataField) !== changedValue
238
+ ) {
239
+ dataSource.setFieldValue(dataField, changedValue);
240
+ }
241
+ }
242
+
243
+ if (onChangeValue) {
244
+ onChangeValue(newValue);
245
+ }
246
+ };
247
+
248
+ const handleOnFocusExit = (event: React.FocusEvent<HTMLInputElement>) => {
249
+ if (onFocusExit) {
250
+ onFocusExit(event);
251
+ }
252
+ };
253
+
254
+ const handleOnFocusEnter = (event: React.FocusEvent<HTMLInputElement>) => {
255
+ if (onFocusEnter) {
256
+ onFocusEnter(event);
257
+ }
258
+ };
259
+
260
+ const isReadOnly = (): boolean => {
261
+ return readOnly || v1v2Compatibility.isReadOnly;
262
+ };
263
+
264
+ // Erro a ser exibido: local ou do contexto
265
+ const displayError = internalError || contextError;
266
+
267
+ const isDark = colorScheme === 'dark';
268
+
269
+ // Mantine-compatible sizing
270
+ const inputHeight =
271
+ size === 'xs'
272
+ ? 30
273
+ : size === 'sm'
274
+ ? 36
275
+ : size === 'md'
276
+ ? 42
277
+ : size === 'lg'
278
+ ? 50
279
+ : size === 'xl'
280
+ ? 60
281
+ : 36;
282
+
283
+ const fontSize =
284
+ size === 'xs'
285
+ ? 12
286
+ : size === 'sm'
287
+ ? 14
288
+ : size === 'md'
289
+ ? 16
290
+ : size === 'lg'
291
+ ? 18
292
+ : size === 'xl'
293
+ ? 20
294
+ : 14;
295
+
296
+ return (
297
+ <Input.Wrapper
298
+ label={label}
299
+ description={description}
300
+ error={displayError}
301
+ required={required}
302
+ size={size}
303
+ style={{ width, ...style }}
304
+ className={className}
305
+ >
306
+ <PhoneInput
307
+ ref={innerComponentRef}
308
+ international={international}
309
+ defaultCountry={defaultCountry}
310
+ value={isDataSourceV2 ? v2Value : currentValue}
311
+ onChange={handleChange}
312
+ onFocus={handleOnFocusEnter}
313
+ onBlur={handleOnFocusExit}
314
+ disabled={disabled}
315
+ readOnly={isReadOnly()}
316
+ placeholder={placeholder}
317
+ style={{
318
+ '--PhoneInputCountryFlag-height': '1em',
319
+ '--PhoneInputCountrySelectArrow-color': isDark
320
+ ? theme.colors.dark[1]
321
+ : theme.colors.gray[6],
322
+ '--PhoneInput-color--focus': theme.colors[theme.primaryColor][isDark ? 4 : 6],
323
+ } as React.CSSProperties}
324
+ numberInputProps={{
325
+ style: {
326
+ height: inputHeight,
327
+ fontSize,
328
+ backgroundColor: isDark ? theme.colors.dark[6] : theme.white,
329
+ color: isDark ? theme.colors.dark[0] : theme.black,
330
+ border: `1px solid ${
331
+ displayError
332
+ ? theme.colors.red[isDark ? 4 : 6]
333
+ : isDark
334
+ ? theme.colors.dark[4]
335
+ : theme.colors.gray[4]
336
+ }`,
337
+ borderRadius: theme.radius.sm,
338
+ paddingLeft: 8,
339
+ paddingRight: 8,
340
+ outline: 'none',
341
+ width: '100%',
342
+ },
343
+ }}
344
+ countrySelectProps={{
345
+ style: {
346
+ backgroundColor: isDark ? theme.colors.dark[6] : theme.white,
347
+ color: isDark ? theme.colors.dark[0] : theme.black,
348
+ },
349
+ }}
350
+ />
351
+ </Input.Wrapper>
352
+ );
353
+ }
354
+
355
+ ArchbasePhoneInput.displayName = 'ArchbasePhoneInput';
@@ -0,0 +1,109 @@
1
+ import React, { useCallback } from 'react';
2
+ import {
3
+ RangeSlider,
4
+ RangeSliderProps,
5
+ Stack,
6
+ Group,
7
+ Text,
8
+ Box,
9
+ } from '@mantine/core';
10
+
11
+ // =============================================================================
12
+ // Types
13
+ // =============================================================================
14
+
15
+ export type RangeValue = [number, number];
16
+
17
+ export interface ArchbaseRangeSliderProps extends Omit<RangeSliderProps, 'value' | 'onChange'> {
18
+ /** Valor atual [min, max] */
19
+ value?: RangeValue;
20
+ /** Callback ao mudar */
21
+ onChange?: (value: RangeValue) => void;
22
+ /** Callback ao soltar o slider */
23
+ onChangeEnd?: (value: RangeValue) => void;
24
+ /** Mostrar valores */
25
+ showValues?: boolean;
26
+ /** Formatador de valores */
27
+ formatValue?: (value: number) => string;
28
+ /** Prefixo dos valores */
29
+ valuePrefix?: string;
30
+ /** Sufixo dos valores */
31
+ valueSuffix?: string;
32
+ }
33
+
34
+ // =============================================================================
35
+ // ArchbaseRangeSlider Component
36
+ // =============================================================================
37
+
38
+ export function ArchbaseRangeSlider({
39
+ value = [0, 100],
40
+ onChange,
41
+ onChangeEnd,
42
+ showValues = true,
43
+ formatValue,
44
+ valuePrefix = '',
45
+ valueSuffix = '',
46
+ min = 0,
47
+ max = 100,
48
+ ...props
49
+ }: ArchbaseRangeSliderProps) {
50
+ const handleChange = useCallback(
51
+ (newValue: RangeValue) => {
52
+ onChange?.(newValue);
53
+ },
54
+ [onChange]
55
+ );
56
+
57
+ const handleChangeEnd = useCallback(
58
+ (newValue: RangeValue) => {
59
+ onChangeEnd?.(newValue);
60
+ },
61
+ [onChangeEnd]
62
+ );
63
+
64
+ const displayValue = (val: number) => {
65
+ if (formatValue) return formatValue(val);
66
+ return `${valuePrefix}${val}${valueSuffix}`;
67
+ };
68
+
69
+ return (
70
+ <Stack gap="xs">
71
+ <RangeSlider
72
+ {...props}
73
+ min={min}
74
+ max={max}
75
+ value={value}
76
+ onChange={handleChange}
77
+ onChangeEnd={handleChangeEnd}
78
+ />
79
+ {showValues && (
80
+ <Group justify="space-between">
81
+ <Text size="sm" c="dimmed">
82
+ Min: {displayValue(value[0])}
83
+ </Text>
84
+ <Text size="sm" c="dimmed">
85
+ Max: {displayValue(value[1])}
86
+ </Text>
87
+ </Group>
88
+ )}
89
+ </Stack>
90
+ );
91
+ }
92
+
93
+ // =============================================================================
94
+ // Convenience Components
95
+ // =============================================================================
96
+
97
+ export function ArchbasePriceRangeSlider(
98
+ props: Omit<ArchbaseRangeSliderProps, 'valuePrefix'>
99
+ ) {
100
+ return <ArchbaseRangeSlider valuePrefix="R$ " {...props} />;
101
+ }
102
+
103
+ export function ArchbasePercentRangeSlider(
104
+ props: Omit<ArchbaseRangeSliderProps, 'valueSuffix' | 'min' | 'max'>
105
+ ) {
106
+ return <ArchbaseRangeSlider min={0} max={100} valueSuffix="%" {...props} />;
107
+ }
108
+
109
+ export default ArchbaseRangeSlider;