frontend-plus-react 0.1.19 → 0.3.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.
package/dist/index.d.ts CHANGED
@@ -1,62 +1,58 @@
1
- import React$1, { ReactNode } from 'react';
2
- import { FieldDefinition, TableDefinition, MenuInfoBase, ProcedureDef, AppConfigClientSetup, DetailTable } from 'backend-plus';
1
+ import React$1, { ReactNode, FC } from 'react';
2
+ import { TableDefinition, FieldDefinition, MenuInfoBase, ProcedureDef, AppConfigClientSetup, DetailTable } from 'backend-plus';
3
3
  export { FieldDefinition, TableDefinition } from 'backend-plus';
4
4
  import { Details } from 'express-useragent';
5
5
  import { RenderCellProps, Column, RenderHeaderCellProps } from 'react-data-grid';
6
6
  import * as react_jsx_runtime from 'react/jsx-runtime';
7
7
 
8
+ /**
9
+ * Recorre recursivamente los hijos de React buscando componentes que tengan una prop 'path'.
10
+ * Esto permite pasar <Route path="..."> o Fragmentos <><Route.../></> y extraer los strings.
11
+ */
12
+ declare const extractPathsFromRoutes: (node: ReactNode) => string[];
13
+
14
+ /**
15
+ * Marca con la que una fila nueva conserva su identidad en la grilla mientras se edita (antes de tener su clave primaria).
16
+ * Es un Symbol: no aparece en Object.keys ni en JSON.stringify, pero el spread de la fila (...fila) la conserva.
17
+ */
18
+ declare const DOM_TEMP_ID: unique symbol;
19
+ /** Una fila de datos de una tabla: los valores salen del servidor ya decodificados (JSON4all) */
20
+ type FilaDeDatos = Record<string, unknown> & {
21
+ [DOM_TEMP_ID]?: string;
22
+ };
8
23
  interface WScreenProps {
9
24
  screenName: string;
25
+ /**
26
+ * Parámetros de la pantalla como objeto plano (en backend-plus, el primer argumento de `mainAction`).
27
+ * Como detalle de una grilla son los fixedFields del detalle; en una ruta, la query string.
28
+ */
29
+ params?: Record<string, unknown>;
10
30
  }
11
- declare let wScreens: Record<string, React$1.FC<WScreenProps>>;
12
- declare const extendWScreens: (newWScreens: Record<string, React$1.FC<WScreenProps>>) => void;
13
-
14
- interface ClientSideProps extends RenderCellProps<any, any> {
31
+ /** Decide, para una fila, si se muestra el botón de un detalle (`condition` del DetailTable) */
32
+ type CondicionDeDetalle = (fila: FilaDeDatos) => boolean;
33
+ type CondicionesMap = Record<string, CondicionDeDetalle>;
34
+ interface ClientSideProps extends RenderCellProps<FilaDeDatos, FilaDeResumen> {
15
35
  fieldDefinition: FieldDefinition;
16
36
  tableDefinition: TableDefinition;
17
37
  primaryKey: string[];
18
38
  }
19
- declare let clientSides: Record<string, React$1.FC<ClientSideProps>>;
20
- declare const extendClientSides: (newRenderers: Record<string, React$1.FC<ClientSideProps>>) => void;
21
-
22
39
  interface ResultOkProps {
23
- data: any;
24
- }
25
- type ResultComponentMap = {
26
- [key: string]: React$1.FC<ResultOkProps>;
27
- };
28
- declare let resultsOk: ResultComponentMap;
29
- declare const extendResultsOk: (newComponents: ResultComponentMap) => void;
30
-
31
- interface RoutesProps {
32
- myRoutes?: React$1.ReactNode;
33
- myUnloggedRoutes?: React$1.ReactNode;
34
- layout?: React$1.ComponentType;
35
- unloggedLayout?: React$1.ComponentType;
40
+ /** Lo que devolvió el procedimiento (la forma depende de cada procedimiento) */
41
+ data: unknown;
36
42
  }
37
- declare function FrontendPlusReactRoutes({ myRoutes, myUnloggedRoutes, layout: Layout, unloggedLayout: UnloggedLayout }: RoutesProps): react_jsx_runtime.JSX.Element;
38
- type WScreenMap = Record<string, React$1.FC<WScreenProps>>;
39
- type ClientSidesMap = Record<string, React$1.FC<ClientSideProps>>;
40
- type ResultsOksMap = Record<string, React$1.FC<ResultOkProps>>;
43
+ type WScreenMap = Record<string, FC<WScreenProps>>;
44
+ type ClientSidesMap = Record<string, FC<ClientSideProps>>;
45
+ type ResultsOksMap = Record<string, FC<ResultOkProps>>;
41
46
  interface AppProps {
42
- myRoutes?: React$1.ReactNode;
43
- myUnloggedRoutes?: React$1.ReactNode;
44
- unloggedLayout?: React$1.ComponentType;
47
+ myRoutes?: ReactNode;
48
+ myUnloggedRoutes?: ReactNode;
49
+ unloggedLayout?: React.ComponentType;
45
50
  myWScreens?: WScreenMap;
46
51
  myClientSides?: ClientSidesMap;
47
52
  myResultsOk?: ResultsOksMap;
53
+ /** Condiciones de los detalles, por nombre (la `condition` de un DetailTable) */
54
+ myConditions?: CondicionesMap;
48
55
  }
49
- declare const FrontendPlusProviders: React$1.FC<{
50
- children: React$1.ReactNode;
51
- publicPaths: string[];
52
- }>;
53
- declare const App: ({ myRoutes, myUnloggedRoutes, unloggedLayout, myWScreens, myClientSides, myResultsOk }: AppProps) => react_jsx_runtime.JSX.Element;
54
-
55
- /**
56
- * Recorre recursivamente los hijos de React buscando componentes que tengan una prop 'path'.
57
- * Esto permite pasar <Route path="..."> o Fragmentos <><Route.../></> y extraer los strings.
58
- */
59
- declare const extractPathsFromRoutes: (node: ReactNode) => string[];
60
56
 
61
57
  interface CellFeedback {
62
58
  rowId: string;
@@ -65,27 +61,38 @@ interface CellFeedback {
65
61
  message?: string;
66
62
  }
67
63
  type CellFeedbackMap = Map<string, CellFeedback>;
68
- interface InputRendererProps<R extends Record<string, any>, S> {
64
+ /** Lo que el manejo de teclas del editor necesita saber de la tecla (sirve para un evento real o uno encolado) */
65
+ type TeclaDeEditor = Pick<React.KeyboardEvent, 'key' | 'target'>;
66
+ interface InputRendererProps<R extends FilaDeDatos, S> {
69
67
  column: Column<R, S>;
70
68
  row: R;
71
69
  rowIdx: number;
72
70
  onRowChange: (row: R, commitChanges?: boolean) => void;
73
71
  onClose: (commitChanges?: boolean, shouldFocusCell?: boolean) => void;
74
72
  tableDefinition: TableDefinition;
75
- cellFeedbackMap: CellFeedbackMap;
76
- setCellFeedbackMap: React.Dispatch<React.SetStateAction<CellFeedbackMap>>;
77
- onKeyPress?: (rowIndex: number, columnKey: string, event: React.KeyboardEvent, handleCommit: (currentValue: any, closeEditor: boolean, focusNextCell: boolean) => Promise<void>) => void;
78
- setTableData: React.Dispatch<React.SetStateAction<any[]>>;
79
- setLocalCellChanges: React.Dispatch<React.SetStateAction<Map<string, Set<string>>>>;
80
- localCellChanges: Map<string, Set<string>>;
73
+ onKeyPress?: (rowIndex: number, columnKey: string, event: TeclaDeEditor, handleCommit: (currentValue: unknown, closeEditor: boolean, focusNextCell: boolean) => Promise<void>) => void;
74
+ /** El editor se registra para recibir las teclas (F4) que caen en la celda antes de que él tenga el foco; devuelve la baja */
75
+ registrarEditor?: (procesar: (key: string) => void) => () => void;
76
+ setTableData: React.Dispatch<React.SetStateAction<FilaDeDatos[]>>;
81
77
  primaryKey: string[];
82
78
  }
79
+ interface Ancestor {
80
+ tableName: string;
81
+ row: FilaDeDatos;
82
+ tableDefinition: TableDefinition;
83
+ fixedFields?: FixedField[];
84
+ }
83
85
  interface GenericDataGridProps$1 {
86
+ tableName: string;
87
+ fixedFields?: FixedField[];
88
+ onOpenDetail?: (tableName: string, fixedFields: FixedField[], label: string, ancestors: Ancestor[]) => void;
89
+ gridStyles?: React.CSSProperties;
90
+ ancestors?: Ancestor[];
84
91
  }
85
92
  interface FixedField {
86
93
  fieldName: string;
87
- value: any;
88
- until?: any;
94
+ value: unknown;
95
+ until?: unknown;
89
96
  }
90
97
  interface ConfirmDialogProps {
91
98
  open: boolean;
@@ -93,13 +100,37 @@ interface ConfirmDialogProps {
93
100
  title: string;
94
101
  message: string;
95
102
  }
96
- interface FilterRendererProps<R extends Record<string, any>, S> {
103
+ /** El filtro de una columna: un texto (busca que contenga) o un operador con su valor */
104
+ type FiltroDeColumna = string | {
105
+ operator?: string;
106
+ value?: string;
107
+ };
108
+ type FiltrosDeGrilla = Record<string, FiltroDeColumna>;
109
+ /** Una entrada de la fila de totales: qué se calculó (suma, promedio...) y su valor */
110
+ type EntradaDeTotal = {
111
+ type: string;
112
+ value: number;
113
+ };
114
+ /** Fila de resumen con los filtros de cada columna (arriba de la grilla, cuando se muestran los filtros) */
115
+ type FilaDeFiltros = {
116
+ id: 'filterRow';
117
+ filters: FiltrosDeGrilla;
118
+ setFilters: React.Dispatch<React.SetStateAction<FiltrosDeGrilla>>;
119
+ };
120
+ /** Fila de resumen con los totales de las columnas que los tienen (pie de la grilla) */
121
+ type FilaDeTotales = {
122
+ id: 'bottomSummaryRow';
123
+ totales: Record<string, EntradaDeTotal>;
124
+ };
125
+ /** Las filas de resumen de react-data-grid: filtros o totales */
126
+ type FilaDeResumen = FilaDeFiltros | FilaDeTotales;
127
+ interface FilterRendererProps<R extends FilaDeDatos, S> {
97
128
  column: Column<R, S>;
98
- filters: Record<string, string>;
99
- setFilters: React.Dispatch<React.SetStateAction<Record<string, string>>>;
129
+ filters: FiltrosDeGrilla;
130
+ setFilters: React.Dispatch<React.SetStateAction<FiltrosDeGrilla>>;
100
131
  }
101
132
  interface GenericDataGridForDetailProps {
102
- parentRow: any;
133
+ parentRow: FilaDeDatos;
103
134
  detailTableDefinition: DetailTable;
104
135
  parentTableName: string;
105
136
  }
@@ -111,7 +142,7 @@ interface MenuListItemProps {
111
142
  level: number;
112
143
  onMenuItemClick?: () => void;
113
144
  }
114
- interface CustomCellProps<R extends Record<string, any>, SR> extends RenderCellProps<R, SR> {
145
+ interface CustomCellProps<R extends FilaDeDatos, SR> extends RenderCellProps<R, SR> {
115
146
  column: RenderCellProps<R, SR>['column'] & {
116
147
  isPK?: boolean;
117
148
  };
@@ -152,10 +183,15 @@ interface SnackbarContextType {
152
183
  interface SnackbarProviderProps {
153
184
  children: ReactNode;
154
185
  }
155
- interface UseApiCallResult<T> {
156
- callApi: (procedureName: string, params: Record<string, any>, opts?: {
157
- reportOnSnackbar: boolean;
158
- }) => Promise<T | undefined>;
186
+ interface CallApiOptions {
187
+ isCritical?: boolean;
188
+ }
189
+ /** Los parámetros de un procedimiento por nombre; se codifican según la definición que manda el servidor */
190
+ type ParametrosDeProcedimiento = Record<string, unknown>;
191
+ interface UseApiCallResult {
192
+ /** R es la forma del resultado de ese procedimiento (el servidor puede no devolver nada: undefined) */
193
+ callApi: <R = unknown>(procedureName: string, params: ParametrosDeProcedimiento, opts?: CallApiOptions) => Promise<R | undefined>;
194
+ callApiUpload: <R = unknown>(procedureName: string, file: File, params: ParametrosDeProcedimiento, opts?: CallApiOptions) => Promise<R | undefined>;
159
195
  loading: boolean;
160
196
  error: Error | null;
161
197
  }
@@ -183,17 +219,66 @@ interface RouterState {
183
219
  redirectPath: string | null;
184
220
  }
185
221
  interface FetchApiOptions extends RequestInit {
222
+ /** No poner Content-Type: lo arma el navegador (por ejemplo con un FormData, que lleva su boundary) */
223
+ sinContentType?: boolean;
224
+ }
225
+ interface DataGridOption {
226
+ id: string;
227
+ label: string;
228
+ icon: React.ReactNode;
229
+ handler: () => Promise<void>;
230
+ visible?: boolean;
186
231
  }
187
232
 
188
233
  interface GenericDataGridProps {
189
234
  tableName: string;
190
235
  fixedFields?: FixedField[];
236
+ /** Abre un detalle en otra pestaña (Ctrl+click o botón del medio en el botón del detalle) */
237
+ onOpenDetail?: (tableName: string, fixedFields: FixedField[], label: string, ancestors: Ancestor[]) => void;
191
238
  gridStyles?: React$1.CSSProperties;
239
+ ancestors?: Ancestor[];
240
+ /** Es una grilla de detalle desplegada dentro de otra grilla */
241
+ anidada?: boolean;
242
+ /** Título a mostrar en lugar del de la tabla (por omisión, el título o nombre de la tabla, igual que la grilla principal) */
243
+ titulo?: string;
244
+ /** Clave en el CacheGrillasContext para volver a mostrarse sin recargar */
245
+ claveCache?: string;
246
+ /** La grilla anidada informa el alto que necesita para mostrarse completa */
247
+ onAltoDeseado?: (alto: number) => void;
248
+ /** La grilla anidada informa el ancho que necesita (sus columnas y los detalles que tenga abiertos) */
249
+ onAnchoDeseado?: (ancho: number) => void;
250
+ /** Alto máximo que puede tener esta grilla anidada (lo calcula la de arriba a partir de la ventana) */
251
+ altoDisponible?: number;
252
+ /**
253
+ * Tope opcional para el alto de las filas de detalle (en px). Sin tope (lo normal) cada detalle
254
+ * se muestra completo, como en backend-plus; con tope, el detalle más alto scrollea por dentro
255
+ * y virtualiza sus propias filas (útil si hay detalles de miles de filas).
256
+ */
257
+ altoMaximoDetalle?: number;
192
258
  }
259
+
193
260
  declare const GenericDataGrid: React$1.FC<GenericDataGridProps>;
194
261
 
262
+ declare let clientSides: Record<string, React$1.FC<ClientSideProps>>;
263
+ declare const extendClientSides: (newRenderers: Record<string, React$1.FC<ClientSideProps>>) => void;
264
+
265
+ declare const extendConditions: (nuevas: CondicionesMap) => void;
266
+
195
267
  declare const ConfirmDialog: React.FC<ConfirmDialogProps>;
196
268
 
269
+ interface RoutesProps {
270
+ myRoutes?: React$1.ReactNode;
271
+ myUnloggedRoutes?: React$1.ReactNode;
272
+ layout?: React$1.ComponentType;
273
+ unloggedLayout?: React$1.ComponentType;
274
+ }
275
+ declare function FrontendPlusReactRoutes({ myRoutes, myUnloggedRoutes, layout: Layout, unloggedLayout: UnloggedLayout }: RoutesProps): react_jsx_runtime.JSX.Element;
276
+ declare const FrontendPlusProviders: React$1.FC<{
277
+ children: React$1.ReactNode;
278
+ publicPaths: string[];
279
+ }>;
280
+ declare const App: ({ myRoutes, myUnloggedRoutes, unloggedLayout, myWScreens, myClientSides, myResultsOk, myConditions }: AppProps) => react_jsx_runtime.JSX.Element;
281
+
197
282
  declare const MainLayout: React$1.FC;
198
283
 
199
284
  declare const SnackbarProvider: React$1.FC<SnackbarProviderProps>;
@@ -210,8 +295,8 @@ declare const useApp: () => {
210
295
  };
211
296
  declare const AppProvider: React$1.FC<AppProviderProps>;
212
297
 
213
- declare const useApiCall: <T = any>() => UseApiCallResult<T>;
214
- declare const useApiCallWithoutSnackbar: <T = any>() => UseApiCallResult<T>;
298
+ declare const useApiCall: () => UseApiCallResult;
299
+ declare const useApiCallWithoutSnackbar: () => UseApiCallResult;
215
300
 
216
301
  /**
217
302
  * Hook personalizado para manejar la lógica de cierre de sesión.
@@ -222,4 +307,13 @@ declare const useLogout: () => () => Promise<void>;
222
307
 
223
308
  declare const cambiarGuionesBajosPorEspacios: (texto: string) => string;
224
309
 
225
- export { App, type AppContextType, type AppProps, AppProvider, type AppProviderProps, type CellFeedback, type CellFeedbackMap, type ClientContextState, type ClientSideProps, type ClientSidesMap, ConfirmDialog, type ConfirmDialogProps, type CustomCellProps, type CustomHeaderCellProps, type FetchApiOptions, type FilterRendererProps, type FixedField, FrontendPlusProviders, FrontendPlusReactRoutes, GenericDataGrid, type GenericDataGridForDetailProps, type GenericDataGridProps$1 as GenericDataGridProps, type InputRendererProps, MainLayout, type MenuListItemProps, type MenuUiState, type PrivateRouteProps, type ResultOkProps, type ResultsOksMap, type RouterState, type SideMenuProps, type SnackbarContextType, SnackbarProvider, type SnackbarProviderProps, type SnackbarState, type UseApiCallResult, type WScreenMap, type WScreenProps, cambiarGuionesBajosPorEspacios, clientSides, extendClientSides, extendResultsOk, extendWScreens, extractPathsFromRoutes, resultsOk as resultComponents, useApiCall, useApiCallWithoutSnackbar, useApp, useLogout, useSnackbar, wScreens };
310
+ declare let wScreens: Record<string, React$1.FC<WScreenProps>>;
311
+ declare const extendWScreens: (newWScreens: Record<string, React$1.FC<WScreenProps>>) => void;
312
+
313
+ type ResultComponentMap = {
314
+ [key: string]: React$1.FC<ResultOkProps>;
315
+ };
316
+ declare let resultsOk: ResultComponentMap;
317
+ declare const extendResultsOk: (newComponents: ResultComponentMap) => void;
318
+
319
+ export { type Ancestor, App, type AppContextType, type AppProps, AppProvider, type AppProviderProps, type CallApiOptions, type CellFeedback, type CellFeedbackMap, type ClientContextState, type ClientSideProps, type ClientSidesMap, type CondicionDeDetalle, type CondicionesMap, ConfirmDialog, type ConfirmDialogProps, type CustomCellProps, type CustomHeaderCellProps, DOM_TEMP_ID, type DataGridOption, type EntradaDeTotal, type FetchApiOptions, type FilaDeDatos, type FilaDeFiltros, type FilaDeResumen, type FilaDeTotales, type FilterRendererProps, type FiltroDeColumna, type FiltrosDeGrilla, type FixedField, FrontendPlusProviders, FrontendPlusReactRoutes, GenericDataGrid, type GenericDataGridForDetailProps, type GenericDataGridProps$1 as GenericDataGridProps, type InputRendererProps, MainLayout, type MenuListItemProps, type MenuUiState, type ParametrosDeProcedimiento, type PrivateRouteProps, type ResultOkProps, type ResultsOksMap, type RouterState, type SideMenuProps, type SnackbarContextType, SnackbarProvider, type SnackbarProviderProps, type SnackbarState, type TeclaDeEditor, type UseApiCallResult, type WScreenMap, type WScreenProps, cambiarGuionesBajosPorEspacios, clientSides, extendClientSides, extendConditions, extendResultsOk, extendWScreens, extractPathsFromRoutes, resultsOk as resultComponents, useApiCall, useApiCallWithoutSnackbar, useApp, useLogout, useSnackbar, wScreens };