flysoft-react-ui 0.4.0 → 0.5.2
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/App.d.ts.map +1 -1
- package/dist/App.js +20 -4
- package/dist/components/form-controls/AutocompleteInput.d.ts +11 -3
- package/dist/components/form-controls/AutocompleteInput.d.ts.map +1 -1
- package/dist/components/form-controls/AutocompleteInput.js +410 -31
- package/dist/components/form-controls/Button.js +1 -1
- package/dist/components/form-controls/Checkbox.d.ts +14 -0
- package/dist/components/form-controls/Checkbox.d.ts.map +1 -0
- package/dist/components/form-controls/Checkbox.js +77 -0
- package/dist/components/form-controls/DateInput.d.ts +20 -4
- package/dist/components/form-controls/DateInput.d.ts.map +1 -1
- package/dist/components/form-controls/DateInput.js +425 -70
- package/dist/components/form-controls/DatePicker.d.ts +4 -3
- package/dist/components/form-controls/DatePicker.d.ts.map +1 -1
- package/dist/components/form-controls/DatePicker.js +26 -30
- package/dist/components/form-controls/Input.d.ts +10 -1
- package/dist/components/form-controls/Input.d.ts.map +1 -1
- package/dist/components/form-controls/Input.js +16 -10
- package/dist/components/form-controls/Pagination.d.ts +1 -0
- package/dist/components/form-controls/Pagination.d.ts.map +1 -1
- package/dist/components/form-controls/Pagination.js +3 -40
- package/dist/components/form-controls/RadioButtonGroup.d.ts +62 -0
- package/dist/components/form-controls/RadioButtonGroup.d.ts.map +1 -0
- package/dist/components/form-controls/RadioButtonGroup.js +220 -0
- package/dist/components/form-controls/SearchSelectInput-OLD.d.ts +68 -0
- package/dist/components/form-controls/SearchSelectInput-OLD.d.ts.map +1 -0
- package/dist/components/form-controls/SearchSelectInput-OLD.js +962 -0
- package/dist/components/form-controls/SearchSelectInput.d.ts +70 -0
- package/dist/components/form-controls/SearchSelectInput.d.ts.map +1 -0
- package/dist/components/form-controls/SearchSelectInput.js +335 -0
- package/dist/components/form-controls/index.d.ts +7 -1
- package/dist/components/form-controls/index.d.ts.map +1 -1
- package/dist/components/form-controls/index.js +3 -0
- package/dist/components/layout/AppLayout.d.ts +3 -2
- package/dist/components/layout/AppLayout.d.ts.map +1 -1
- package/dist/components/layout/AppLayout.js +104 -31
- package/dist/components/layout/Card.d.ts +4 -1
- package/dist/components/layout/Card.d.ts.map +1 -1
- package/dist/components/layout/Card.js +30 -1
- package/dist/components/layout/Collection.js +1 -1
- package/dist/components/layout/DataTable.d.ts +29 -0
- package/dist/components/layout/DataTable.d.ts.map +1 -0
- package/dist/components/layout/DataTable.js +165 -0
- package/dist/components/layout/index.d.ts +2 -0
- package/dist/components/layout/index.d.ts.map +1 -1
- package/dist/components/layout/index.js +1 -0
- package/dist/components/utils/Avatar.d.ts +49 -0
- package/dist/components/utils/Avatar.d.ts.map +1 -0
- package/dist/components/utils/Avatar.js +93 -0
- package/dist/components/utils/Badge.d.ts +3 -0
- package/dist/components/utils/Badge.d.ts.map +1 -1
- package/dist/components/utils/Badge.js +130 -26
- package/dist/components/utils/Dialog.d.ts.map +1 -1
- package/dist/components/utils/Dialog.js +5 -1
- package/dist/components/utils/DropdownMenu.d.ts +25 -0
- package/dist/components/utils/DropdownMenu.d.ts.map +1 -0
- package/dist/components/utils/DropdownMenu.js +145 -0
- package/dist/components/utils/Filter.d.ts +57 -0
- package/dist/components/utils/Filter.d.ts.map +1 -0
- package/dist/components/utils/Filter.js +580 -0
- package/dist/components/utils/FiltersDialog.d.ts +21 -0
- package/dist/components/utils/FiltersDialog.d.ts.map +1 -0
- package/dist/components/utils/FiltersDialog.js +104 -0
- package/dist/components/utils/Loader.js +1 -1
- package/dist/components/utils/RoadMap.d.ts +59 -0
- package/dist/components/utils/RoadMap.d.ts.map +1 -0
- package/dist/components/utils/RoadMap.js +138 -0
- package/dist/components/utils/Snackbar.d.ts +13 -0
- package/dist/components/utils/Snackbar.d.ts.map +1 -0
- package/dist/components/utils/Snackbar.js +121 -0
- package/dist/components/utils/SnackbarContainer.d.ts +7 -0
- package/dist/components/utils/SnackbarContainer.d.ts.map +1 -0
- package/dist/components/utils/SnackbarContainer.js +25 -0
- package/dist/components/utils/index.d.ts +12 -0
- package/dist/components/utils/index.d.ts.map +1 -1
- package/dist/components/utils/index.js +6 -0
- package/dist/contexts/AppLayoutContext.d.ts +40 -0
- package/dist/contexts/AppLayoutContext.d.ts.map +1 -0
- package/dist/contexts/AppLayoutContext.js +98 -0
- package/dist/contexts/ListCrudContext.d.ts +29 -0
- package/dist/contexts/ListCrudContext.d.ts.map +1 -0
- package/dist/contexts/ListCrudContext.js +209 -0
- package/dist/contexts/SnackbarContext.d.ts +26 -0
- package/dist/contexts/SnackbarContext.d.ts.map +1 -0
- package/dist/contexts/SnackbarContext.js +34 -0
- package/dist/contexts/index.d.ts +6 -0
- package/dist/contexts/index.d.ts.map +1 -1
- package/dist/contexts/index.js +6 -0
- package/dist/contexts/presets.js +6 -6
- package/dist/docs/AuthDocs.tsx/AuthDocsContent.js +3 -1
- package/dist/docs/AvatarDocs.d.ts +4 -0
- package/dist/docs/AvatarDocs.d.ts.map +1 -0
- package/dist/docs/AvatarDocs.js +7 -0
- package/dist/docs/BadgeDocs.d.ts.map +1 -1
- package/dist/docs/BadgeDocs.js +4 -2
- package/dist/docs/CardDocs.d.ts.map +1 -1
- package/dist/docs/CardDocs.js +7 -1
- package/dist/docs/CheckboxDocs.d.ts +4 -0
- package/dist/docs/CheckboxDocs.d.ts.map +1 -0
- package/dist/docs/CheckboxDocs.js +7 -0
- package/dist/docs/DataTableDocs.d.ts +4 -0
- package/dist/docs/DataTableDocs.d.ts.map +1 -0
- package/dist/docs/DataTableDocs.js +244 -0
- package/dist/docs/DateInputDocs.d.ts +1 -0
- package/dist/docs/DateInputDocs.d.ts.map +1 -1
- package/dist/docs/DateInputDocs.js +7 -9
- package/dist/docs/DatePickerDocs.d.ts +1 -0
- package/dist/docs/DatePickerDocs.d.ts.map +1 -1
- package/dist/docs/DatePickerDocs.js +6 -8
- package/dist/docs/DocAdmin.d.ts +4 -0
- package/dist/docs/DocAdmin.d.ts.map +1 -0
- package/dist/docs/DocAdmin.js +68 -0
- package/dist/docs/DocsMenu.d.ts.map +1 -1
- package/dist/docs/DocsMenu.js +1 -1
- package/dist/docs/DocsRouter.d.ts.map +1 -1
- package/dist/docs/DocsRouter.js +13 -1
- package/dist/docs/DropdownMenuDocs.d.ts +4 -0
- package/dist/docs/DropdownMenuDocs.d.ts.map +1 -0
- package/dist/docs/DropdownMenuDocs.js +66 -0
- package/dist/docs/ExampleFormDocs.d.ts +4 -0
- package/dist/docs/ExampleFormDocs.d.ts.map +1 -0
- package/dist/docs/ExampleFormDocs.js +148 -0
- package/dist/docs/FilterDocs.d.ts +4 -0
- package/dist/docs/FilterDocs.d.ts.map +1 -0
- package/dist/docs/FilterDocs.js +112 -0
- package/dist/docs/InputDocs.d.ts.map +1 -1
- package/dist/docs/InputDocs.js +11 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts +11 -0
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts.map +1 -0
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.js +25 -0
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts +2 -0
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts.map +1 -0
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.js +51 -0
- package/dist/docs/PaginationDocs.js +6 -6
- package/dist/docs/RadioButtonGroupDocs.d.ts +4 -0
- package/dist/docs/RadioButtonGroupDocs.d.ts.map +1 -0
- package/dist/docs/RadioButtonGroupDocs.js +46 -0
- package/dist/docs/RoadMapDocs.d.ts +4 -0
- package/dist/docs/RoadMapDocs.d.ts.map +1 -0
- package/dist/docs/RoadMapDocs.js +171 -0
- package/dist/docs/SearchSelectInputDocs.d.ts +4 -0
- package/dist/docs/SearchSelectInputDocs.d.ts.map +1 -0
- package/dist/docs/SearchSelectInputDocs.js +168 -0
- package/dist/docs/SnackbarDocs.d.ts +4 -0
- package/dist/docs/SnackbarDocs.d.ts.map +1 -0
- package/dist/docs/SnackbarDocs.js +50 -0
- package/dist/docs/TabsGroupDocs.d.ts.map +1 -1
- package/dist/docs/TabsGroupDocs.js +12 -1
- package/dist/docs/docMockServices/empresaService.d.ts +38 -0
- package/dist/docs/docMockServices/empresaService.d.ts.map +1 -0
- package/dist/docs/docMockServices/empresaService.js +116 -0
- package/dist/docs/docMockServices/index.d.ts +9 -0
- package/dist/docs/docMockServices/index.d.ts.map +1 -0
- package/dist/docs/docMockServices/index.js +8 -0
- package/dist/docs/docMockServices/initialData.d.ts +6 -0
- package/dist/docs/docMockServices/initialData.d.ts.map +1 -0
- package/dist/docs/docMockServices/initialData.js +132 -0
- package/dist/docs/docMockServices/interfaces.d.ts +26 -0
- package/dist/docs/docMockServices/interfaces.d.ts.map +1 -0
- package/dist/docs/docMockServices/interfaces.js +1 -0
- package/dist/docs/docMockServices/personaEmpresaService.d.ts +43 -0
- package/dist/docs/docMockServices/personaEmpresaService.d.ts.map +1 -0
- package/dist/docs/docMockServices/personaEmpresaService.js +113 -0
- package/dist/docs/docMockServices/personaService.d.ts +39 -0
- package/dist/docs/docMockServices/personaService.d.ts.map +1 -0
- package/dist/docs/docMockServices/personaService.js +180 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useAsyncRequest.d.ts +17 -0
- package/dist/hooks/useAsyncRequest.d.ts.map +1 -0
- package/dist/hooks/useAsyncRequest.js +70 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { type InputProps } from "./Input";
|
|
3
|
+
import type { PaginationInterface } from "./Pagination";
|
|
4
|
+
export interface SearchSelectOption {
|
|
5
|
+
label: string;
|
|
6
|
+
value?: string;
|
|
7
|
+
description?: string | number;
|
|
8
|
+
icon?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SearchSelectInputProps<T = SearchSelectOption, K = string> extends Omit<InputProps, "onChange" | "value" | "ref"> {
|
|
11
|
+
value?: T | K | string;
|
|
12
|
+
/**
|
|
13
|
+
* Callback cuando cambia el valor del input.
|
|
14
|
+
* Recibe la opción completa (T) si no hay getOptionValue, o el valor extraído (K) si hay getOptionValue.
|
|
15
|
+
* También es compatible con react-hook-form: acepta el onChange estándar de HTML.
|
|
16
|
+
*/
|
|
17
|
+
onChange?: ((value: T | K) => void) | React.ChangeEventHandler<HTMLInputElement>;
|
|
18
|
+
/**
|
|
19
|
+
* Función que realiza la búsqueda y devuelve un Promise con los resultados
|
|
20
|
+
*/
|
|
21
|
+
onSearchPromiseFn: (text: string) => Promise<Array<T> | PaginationInterface<T>>;
|
|
22
|
+
/**
|
|
23
|
+
* Función que busca un elemento individual usando su valor (K).
|
|
24
|
+
* Se usa cuando hay un valor por defecto que no está presente en las opciones cargadas.
|
|
25
|
+
* Recibe el valor (K) y devuelve una Promise con el objeto completo (T) o undefined si no se encuentra.
|
|
26
|
+
*/
|
|
27
|
+
onSingleSearchPromiseFn: (value: K) => Promise<T | undefined>;
|
|
28
|
+
/**
|
|
29
|
+
* Callback al seleccionar una opción. Devuelve el item completo (T) y el valor mapeado (K)
|
|
30
|
+
*/
|
|
31
|
+
onSelectOption?: (option: T, value: K) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Título del dialog de selección. Por defecto "Seleccione una opción"
|
|
34
|
+
*/
|
|
35
|
+
dialogTitle?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Posición del botón de búsqueda. Por defecto "right"
|
|
38
|
+
*/
|
|
39
|
+
icon?: string;
|
|
40
|
+
iconPosition?: "left" | "right";
|
|
41
|
+
/**
|
|
42
|
+
* Texto a mostrar cuando no hay resultados
|
|
43
|
+
*/
|
|
44
|
+
noResultsText?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Obtiene el label que se muestra para cada opción. Por defecto usa la propiedad "label".
|
|
47
|
+
*/
|
|
48
|
+
getOptionLabel?: (item: T) => string;
|
|
49
|
+
/**
|
|
50
|
+
* Obtiene el valor que se devuelve al seleccionar una opción. Por defecto usa la propiedad "value".
|
|
51
|
+
*/
|
|
52
|
+
getOptionValue?: (item: T) => K;
|
|
53
|
+
/**
|
|
54
|
+
* Obtiene la descripción opcional para cada opción. Por defecto usa la propiedad "description".
|
|
55
|
+
*/
|
|
56
|
+
getOptionDescription?: (item: T) => string | number | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Renderizado personalizado de cada opción. Si se define, se ignora el render por defecto.
|
|
59
|
+
*/
|
|
60
|
+
renderOption?: (item: T) => React.ReactNode;
|
|
61
|
+
/**
|
|
62
|
+
* Si es true, el input será de solo lectura. No se podrá modificar ni abrir el diálogo de selección.
|
|
63
|
+
* Por defecto es false.
|
|
64
|
+
*/
|
|
65
|
+
readOnly?: boolean;
|
|
66
|
+
}
|
|
67
|
+
export declare const SearchSelectInput: <T = SearchSelectOption, K = string>(props: SearchSelectInputProps<T, K> & {
|
|
68
|
+
ref?: React.ForwardedRef<HTMLInputElement>;
|
|
69
|
+
}) => React.ReactElement;
|
|
70
|
+
//# sourceMappingURL=SearchSelectInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchSelectInput.d.ts","sourceRoot":"","sources":["../../../src/components/form-controls/SearchSelectInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAMN,MAAM,OAAO,CAAC;AAEf,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAIxD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AACD,MAAM,WAAW,sBAAsB,CAAC,CAAC,GAAG,kBAAkB,EAAE,CAAC,GAAG,MAAM,CACxE,SAAQ,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC;IACtD,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,EACL,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,GACxB,KAAK,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;IAC/C;;OAEG;IACH,iBAAiB,EAAE,CACjB,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD;;;;OAIG;IACH,uBAAuB,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC9D;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC/C;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IACrC;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;IAChC;;OAEG;IACH,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAChE;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC5C;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsfD,eAAO,MAAM,iBAAiB,EAA6B,CACzD,CAAC,GAAG,kBAAkB,EACtB,CAAC,GAAG,MAAM,EAEV,KAAK,EAAE,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IACpC,GAAG,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;CAC5C,KACE,KAAK,CAAC,YAAY,CAAC"}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState, useMemo, useRef, useCallback, useEffect, } from "react";
|
|
3
|
+
import { useFormContext } from "react-hook-form";
|
|
4
|
+
import { Input } from "./Input";
|
|
5
|
+
import { Button } from "./Button";
|
|
6
|
+
import { Dialog, Loader } from "../utils";
|
|
7
|
+
const SearchSelectInputInner = React.forwardRef(function SearchSelectInput({ value, onChange, onSearchPromiseFn, onSingleSearchPromiseFn, onSelectOption, dialogTitle = "Seleccione una opción", icon = "fa-search", iconPosition = "right", noResultsText = "Sin resultados", getOptionLabel, getOptionValue, getOptionDescription, renderOption, label, readOnly = false, ...inputProps }, ref) {
|
|
8
|
+
const [inputText, setInputText] = useState("");
|
|
9
|
+
const [dialogInputText, setDialogInputText] = useState("");
|
|
10
|
+
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
11
|
+
const [options, setOptions] = useState([]);
|
|
12
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
13
|
+
const [hasSearched, setHasSearched] = useState(false);
|
|
14
|
+
const inputRef = useRef(null);
|
|
15
|
+
const dialogInputRef = useRef(null);
|
|
16
|
+
const justClearedRef = useRef(false);
|
|
17
|
+
// Detectar modo register
|
|
18
|
+
const isRegisterMode = useMemo(() => {
|
|
19
|
+
return "name" in inputProps && inputProps.name !== undefined;
|
|
20
|
+
}, [inputProps]);
|
|
21
|
+
const fieldName = isRegisterMode && "name" in inputProps
|
|
22
|
+
? inputProps.name
|
|
23
|
+
: undefined;
|
|
24
|
+
// Obtener setValue del contexto del formulario
|
|
25
|
+
// Para usar con register, el formulario debe estar dentro de FormProvider
|
|
26
|
+
// useFormContext debe llamarse incondicionalmente (requisito de React Hooks)
|
|
27
|
+
// Si no hay FormProvider y se usa en modo register, useFormContext lanzará un error
|
|
28
|
+
// Para usar sin FormProvider, usar Controller en lugar de register
|
|
29
|
+
const formContext = useFormContext();
|
|
30
|
+
const setValue = formContext?.setValue;
|
|
31
|
+
// Combinar refs
|
|
32
|
+
const combinedRef = useCallback((node) => {
|
|
33
|
+
inputRef.current = node;
|
|
34
|
+
if (typeof ref === "function") {
|
|
35
|
+
ref(node);
|
|
36
|
+
}
|
|
37
|
+
else if (ref) {
|
|
38
|
+
ref.current = node;
|
|
39
|
+
}
|
|
40
|
+
}, [ref]);
|
|
41
|
+
const valueGetter = useCallback((item) => {
|
|
42
|
+
if (getOptionValue)
|
|
43
|
+
return getOptionValue(item);
|
|
44
|
+
return item["value"];
|
|
45
|
+
}, [getOptionValue]);
|
|
46
|
+
const labelGetter = useCallback((item) => {
|
|
47
|
+
if (getOptionLabel)
|
|
48
|
+
return getOptionLabel(item);
|
|
49
|
+
return item["label"];
|
|
50
|
+
}, [getOptionLabel]);
|
|
51
|
+
const descriptionGetter = useCallback((item) => {
|
|
52
|
+
if (getOptionDescription)
|
|
53
|
+
return getOptionDescription(item);
|
|
54
|
+
return item["description"];
|
|
55
|
+
}, [getOptionDescription]);
|
|
56
|
+
const handleSearch = async (text) => {
|
|
57
|
+
setIsLoading(true);
|
|
58
|
+
setHasSearched(true);
|
|
59
|
+
const options = await onSearchPromiseFn(text);
|
|
60
|
+
if (options instanceof Array) {
|
|
61
|
+
setOptions(options);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
setOptions(options.list);
|
|
65
|
+
}
|
|
66
|
+
setIsLoading(false);
|
|
67
|
+
};
|
|
68
|
+
const handleSelect = (option) => {
|
|
69
|
+
const selectedValue = valueGetter(option);
|
|
70
|
+
setIsDialogOpen(false);
|
|
71
|
+
// En modo register, setear el valor usando setValue o actualizando el input nativo
|
|
72
|
+
if (isRegisterMode) {
|
|
73
|
+
if (setValue && fieldName) {
|
|
74
|
+
setValue(fieldName, selectedValue, {
|
|
75
|
+
shouldValidate: true,
|
|
76
|
+
shouldDirty: true,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
else if (inputRef.current) {
|
|
80
|
+
const nativeInput = inputRef.current;
|
|
81
|
+
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set;
|
|
82
|
+
if (nativeInputValueSetter) {
|
|
83
|
+
nativeInputValueSetter.call(nativeInput, String(selectedValue ?? ""));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
nativeInput.value = String(selectedValue ?? "");
|
|
87
|
+
}
|
|
88
|
+
if (onChange) {
|
|
89
|
+
const changeEvent = {
|
|
90
|
+
target: nativeInput,
|
|
91
|
+
currentTarget: nativeInput,
|
|
92
|
+
};
|
|
93
|
+
onChange(changeEvent);
|
|
94
|
+
}
|
|
95
|
+
const inputEvent = new Event("input", {
|
|
96
|
+
bubbles: true,
|
|
97
|
+
cancelable: true,
|
|
98
|
+
});
|
|
99
|
+
nativeInput.dispatchEvent(inputEvent);
|
|
100
|
+
const changeEventNative = new Event("change", {
|
|
101
|
+
bubbles: true,
|
|
102
|
+
cancelable: true,
|
|
103
|
+
});
|
|
104
|
+
nativeInput.dispatchEvent(changeEventNative);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
onChange?.(selectedValue);
|
|
109
|
+
}
|
|
110
|
+
onSelectOption?.(option, selectedValue);
|
|
111
|
+
setInputText(labelGetter(option));
|
|
112
|
+
setDialogInputText("");
|
|
113
|
+
setOptions([]);
|
|
114
|
+
setHasSearched(false);
|
|
115
|
+
};
|
|
116
|
+
// Función para sincronizar inputText con un valor
|
|
117
|
+
const syncInputText = useCallback((currentValue) => {
|
|
118
|
+
if (currentValue === undefined ||
|
|
119
|
+
currentValue === null ||
|
|
120
|
+
currentValue === "") {
|
|
121
|
+
setInputText("");
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// Si currentValue es un objeto (T) y tenemos getOptionLabel, usar directamente
|
|
125
|
+
if (typeof currentValue === "object" &&
|
|
126
|
+
getOptionLabel &&
|
|
127
|
+
!getOptionValue) {
|
|
128
|
+
try {
|
|
129
|
+
const label = getOptionLabel(currentValue);
|
|
130
|
+
setInputText(label);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// Si falla, continuar con la búsqueda normal
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Normalizar el value: si es un objeto (T), extraer el valor usando valueGetter
|
|
138
|
+
let valueToSearch = currentValue;
|
|
139
|
+
if (typeof currentValue === "object" && getOptionValue) {
|
|
140
|
+
// Si currentValue es un objeto y tenemos getOptionValue, extraer el valor
|
|
141
|
+
try {
|
|
142
|
+
valueToSearch = getOptionValue(currentValue);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Si falla, no podemos usar onSingleSearchPromiseFn con un objeto
|
|
146
|
+
// Intentar mostrar el label directamente si está disponible
|
|
147
|
+
if (getOptionLabel) {
|
|
148
|
+
try {
|
|
149
|
+
setInputText(getOptionLabel(currentValue));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
setInputText(String(currentValue));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
setInputText(String(currentValue));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Buscar en las opciones actuales
|
|
162
|
+
const matchingOption = options.find((opt) => valueGetter(opt) === valueToSearch ||
|
|
163
|
+
valueGetter(opt) === currentValue);
|
|
164
|
+
if (matchingOption) {
|
|
165
|
+
setInputText(labelGetter(matchingOption));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// Si no se encuentra en las opciones actuales, usar onSingleSearchPromiseFn
|
|
169
|
+
if (onSingleSearchPromiseFn &&
|
|
170
|
+
valueToSearch !== undefined &&
|
|
171
|
+
valueToSearch !== null) {
|
|
172
|
+
onSingleSearchPromiseFn(valueToSearch)
|
|
173
|
+
.then((foundOption) => {
|
|
174
|
+
if (foundOption) {
|
|
175
|
+
setInputText(labelGetter(foundOption));
|
|
176
|
+
// Agregar la opción a las opciones disponibles si no está ya
|
|
177
|
+
setOptions((prev) => {
|
|
178
|
+
if (!prev.find((opt) => valueGetter(opt) === valueGetter(foundOption))) {
|
|
179
|
+
return [...prev, foundOption];
|
|
180
|
+
}
|
|
181
|
+
return prev;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
// Si no se encuentra, mostrar el valor como string
|
|
186
|
+
setInputText(String(valueToSearch));
|
|
187
|
+
}
|
|
188
|
+
})
|
|
189
|
+
.catch((error) => {
|
|
190
|
+
console.error("Error al buscar opción individual:", error);
|
|
191
|
+
setInputText(String(valueToSearch));
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
// Si no hay onSingleSearchPromiseFn, mostrar el valor como string
|
|
196
|
+
setInputText(String(valueToSearch));
|
|
197
|
+
}
|
|
198
|
+
}, [
|
|
199
|
+
options,
|
|
200
|
+
getOptionValue,
|
|
201
|
+
getOptionLabel,
|
|
202
|
+
onSingleSearchPromiseFn,
|
|
203
|
+
valueGetter,
|
|
204
|
+
labelGetter,
|
|
205
|
+
]);
|
|
206
|
+
// Sincronizar inputText cuando cambia el value (modo controlado)
|
|
207
|
+
useEffect(() => {
|
|
208
|
+
if (!isRegisterMode) {
|
|
209
|
+
syncInputText(value);
|
|
210
|
+
}
|
|
211
|
+
}, [value, isRegisterMode, syncInputText]);
|
|
212
|
+
// Sincronizar inputText cuando cambia el valor del formulario (modo register)
|
|
213
|
+
useEffect(() => {
|
|
214
|
+
if (isRegisterMode && formContext && fieldName) {
|
|
215
|
+
// Sincronizar inicialmente
|
|
216
|
+
const formValue = formContext.watch(fieldName);
|
|
217
|
+
syncInputText(formValue);
|
|
218
|
+
// Suscribirse a cambios del formulario
|
|
219
|
+
const subscription = formContext.watch((_data, { name }) => {
|
|
220
|
+
// Solo sincronizar cuando cambia el campo específico
|
|
221
|
+
if (name === fieldName) {
|
|
222
|
+
const currentFormValue = formContext.watch(fieldName);
|
|
223
|
+
syncInputText(currentFormValue);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
return () => subscription.unsubscribe();
|
|
227
|
+
}
|
|
228
|
+
}, [isRegisterMode, formContext, fieldName, syncInputText]);
|
|
229
|
+
// Hacer blur en el input del dialog cuando se abre
|
|
230
|
+
useEffect(() => {
|
|
231
|
+
if (isDialogOpen) {
|
|
232
|
+
// El Dialog renderiza condicionalmente, así que necesitamos esperar a que el input esté montado
|
|
233
|
+
// Usar requestAnimationFrame doble para asegurar que el DOM esté completamente renderizado
|
|
234
|
+
const timeoutId = setTimeout(() => {
|
|
235
|
+
requestAnimationFrame(() => {
|
|
236
|
+
dialogInputRef.current?.focus();
|
|
237
|
+
});
|
|
238
|
+
}, 50);
|
|
239
|
+
return () => clearTimeout(timeoutId);
|
|
240
|
+
}
|
|
241
|
+
}, [isDialogOpen]);
|
|
242
|
+
const getDialogBody = () => {
|
|
243
|
+
return (_jsxs("div", { children: [_jsx("div", { className: "mb-2", children: _jsx(Input, { ref: dialogInputRef, value: dialogInputText, onChange: (e) => setDialogInputText(e.target.value), icon: icon, iconPosition: iconPosition, onIconClick: () => handleSearch(dialogInputText), onKeyDown: (e) => {
|
|
244
|
+
if (e.key === "Enter") {
|
|
245
|
+
e.preventDefault();
|
|
246
|
+
handleSearch(dialogInputText);
|
|
247
|
+
}
|
|
248
|
+
} }) }), _jsx("div", { children: _jsx(Loader, { isLoading: isLoading, children: !hasSearched || options.length > 0 ? (_jsx("ul", { className: "space-y-1 max-h-96 overflow-y-auto", children: _jsx("ul", { className: "space-y-1 max-h-96 overflow-y-auto", children: options.map((option, index) => {
|
|
249
|
+
const label = labelGetter(option);
|
|
250
|
+
const description = descriptionGetter(option);
|
|
251
|
+
const anyOption = option;
|
|
252
|
+
return (_jsx("li", { className: "px-3 py-2 cursor-pointer rounded-md flex items-start gap-2 text-sm\r\n text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] transition-colors", onClick: () => handleSelect(option), children: renderOption ? (renderOption(option)) : (_jsxs(_Fragment, { children: [anyOption.icon && (_jsx("i", { className: `fa ${anyOption.icon} mt-0.5 text-[var(--color-text-muted)]` })), _jsxs("div", { className: "flex flex-col flex-1", children: [_jsx("span", { className: "font-[var(--font-default)]", children: label }), description !== undefined &&
|
|
253
|
+
description !== null && (_jsx("span", { className: "text-xs text-[var(--color-text-secondary)]", children: description }))] })] })) }, String(valueGetter(option) ?? label ?? index)));
|
|
254
|
+
}) }) })) : (_jsx("div", { className: "px-3 py-8 text-center text-sm text-[var(--color-text-secondary)]", children: noResultsText })) }) })] }));
|
|
255
|
+
};
|
|
256
|
+
// Detectar si hay un valor seleccionado
|
|
257
|
+
const hasValue = inputText !== "" && inputText !== undefined && inputText !== null;
|
|
258
|
+
// Función para limpiar el valor y abrir el dialog
|
|
259
|
+
const handleIconClick = useCallback((event) => {
|
|
260
|
+
if (readOnly)
|
|
261
|
+
return;
|
|
262
|
+
event.preventDefault();
|
|
263
|
+
event.stopPropagation();
|
|
264
|
+
if (hasValue) {
|
|
265
|
+
// Si hay valor, limpiarlo
|
|
266
|
+
// Marcar que acabamos de limpiar para prevenir que onFocus abra el diálogo
|
|
267
|
+
justClearedRef.current = true;
|
|
268
|
+
if (isRegisterMode) {
|
|
269
|
+
if (setValue && fieldName) {
|
|
270
|
+
setValue(fieldName, undefined, {
|
|
271
|
+
shouldValidate: true,
|
|
272
|
+
shouldDirty: true,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
else if (inputRef.current) {
|
|
276
|
+
const nativeInput = inputRef.current;
|
|
277
|
+
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set;
|
|
278
|
+
if (nativeInputValueSetter) {
|
|
279
|
+
nativeInputValueSetter.call(nativeInput, "");
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
nativeInput.value = "";
|
|
283
|
+
}
|
|
284
|
+
if (onChange) {
|
|
285
|
+
const changeEvent = {
|
|
286
|
+
target: nativeInput,
|
|
287
|
+
currentTarget: nativeInput,
|
|
288
|
+
};
|
|
289
|
+
onChange(changeEvent);
|
|
290
|
+
}
|
|
291
|
+
const inputEvent = new Event("input", {
|
|
292
|
+
bubbles: true,
|
|
293
|
+
cancelable: true,
|
|
294
|
+
});
|
|
295
|
+
nativeInput.dispatchEvent(inputEvent);
|
|
296
|
+
const changeEventNative = new Event("change", {
|
|
297
|
+
bubbles: true,
|
|
298
|
+
cancelable: true,
|
|
299
|
+
});
|
|
300
|
+
nativeInput.dispatchEvent(changeEventNative);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
onChange?.(undefined);
|
|
305
|
+
}
|
|
306
|
+
setInputText("");
|
|
307
|
+
setIsDialogOpen(false);
|
|
308
|
+
// Resetear el flag después de un pequeño delay para permitir que otros eventos se procesen
|
|
309
|
+
setTimeout(() => {
|
|
310
|
+
justClearedRef.current = false;
|
|
311
|
+
}, 100);
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
// Si no hay valor, abrir el dialog
|
|
315
|
+
setIsDialogOpen(true);
|
|
316
|
+
}
|
|
317
|
+
}, [hasValue, isRegisterMode, setValue, fieldName, onChange, readOnly]);
|
|
318
|
+
// Determinar qué ícono mostrar: si hay valor, mostrar "fa-times", sino el ícono original
|
|
319
|
+
// Si está en readOnly, no mostrar ningún ícono
|
|
320
|
+
const displayIcon = readOnly ? undefined : hasValue ? "fa-times" : icon;
|
|
321
|
+
const displayIconPosition = readOnly ? undefined : iconPosition;
|
|
322
|
+
const displayOnIconClick = readOnly ? undefined : handleIconClick;
|
|
323
|
+
return (_jsxs(_Fragment, { children: [_jsx(Input, { ...inputProps, ref: combinedRef, label: label, value: inputText, onChange: (e) => {
|
|
324
|
+
if (readOnly)
|
|
325
|
+
return;
|
|
326
|
+
setInputText(e.target.value);
|
|
327
|
+
}, onFocus: () => {
|
|
328
|
+
if (!readOnly && !justClearedRef.current) {
|
|
329
|
+
setIsDialogOpen(true);
|
|
330
|
+
}
|
|
331
|
+
}, icon: displayIcon, iconPosition: displayIconPosition, onIconClick: displayOnIconClick, readOnly: readOnly }), !readOnly && (_jsx(Dialog, { isOpen: isDialogOpen, title: dialogTitle, dialogBody: getDialogBody(), dialogActions: _jsx(Button, { variant: "outline", onClick: () => setIsDialogOpen(false), children: "Cerrar" }), onClose: () => setIsDialogOpen(false) }))] }));
|
|
332
|
+
});
|
|
333
|
+
SearchSelectInputInner.displayName = "SearchSelectInput";
|
|
334
|
+
// Exportar con el cast genérico para permitir uso como <SearchSelectInput<T, K>>
|
|
335
|
+
export const SearchSelectInput = SearchSelectInputInner;
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
export { Button } from "./Button";
|
|
2
2
|
export { Input } from "./Input";
|
|
3
3
|
export { AutocompleteInput } from "./AutocompleteInput";
|
|
4
|
+
export { SearchSelectInput } from "./SearchSelectInput-OLD";
|
|
4
5
|
export { DatePicker } from "./DatePicker";
|
|
5
6
|
export { DateInput } from "./DateInput";
|
|
6
7
|
export { Pagination } from "./Pagination";
|
|
8
|
+
export { Checkbox } from "./Checkbox";
|
|
9
|
+
export { RadioButtonGroup } from "./RadioButtonGroup";
|
|
7
10
|
export type { ButtonProps } from "./Button";
|
|
8
11
|
export type { InputProps } from "./Input";
|
|
9
12
|
export type { AutocompleteInputProps, AutocompleteOption, } from "./AutocompleteInput";
|
|
13
|
+
export type { SearchSelectInputProps, SearchSelectOption, } from "./SearchSelectInput-OLD";
|
|
10
14
|
export type { DatePickerProps } from "./DatePicker";
|
|
11
15
|
export type { DateInputProps, DateInputFormat } from "./DateInput";
|
|
12
|
-
export type { PaginationProps, PaginationInterface
|
|
16
|
+
export type { PaginationProps, PaginationInterface } from "./Pagination";
|
|
17
|
+
export type { CheckboxProps } from "./Checkbox";
|
|
18
|
+
export type { RadioButtonGroupProps, RadioOption } from "./RadioButtonGroup";
|
|
13
19
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/form-controls/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1C,YAAY,EACV,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/form-controls/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1C,YAAY,EACV,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACzE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,YAAY,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export { Button } from "./Button";
|
|
2
2
|
export { Input } from "./Input";
|
|
3
3
|
export { AutocompleteInput } from "./AutocompleteInput";
|
|
4
|
+
export { SearchSelectInput } from "./SearchSelectInput-OLD";
|
|
4
5
|
export { DatePicker } from "./DatePicker";
|
|
5
6
|
export { DateInput } from "./DateInput";
|
|
6
7
|
export { Pagination } from "./Pagination";
|
|
8
|
+
export { Checkbox } from "./Checkbox";
|
|
9
|
+
export { RadioButtonGroup } from "./RadioButtonGroup";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import type { NavbarInterface, LeftDrawerInterface } from "../../contexts/AppLayoutContext";
|
|
2
3
|
export interface AppLayoutProps {
|
|
3
|
-
|
|
4
|
-
leftDrawer?:
|
|
4
|
+
navbar?: NavbarInterface;
|
|
5
|
+
leftDrawer?: LeftDrawerInterface;
|
|
5
6
|
children: React.ReactNode;
|
|
6
7
|
className?: string;
|
|
7
8
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppLayout.d.ts","sourceRoot":"","sources":["../../../src/components/layout/AppLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2B,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"AppLayout.d.ts","sourceRoot":"","sources":["../../../src/components/layout/AppLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2B,MAAM,OAAO,CAAC;AAIhD,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,MAAM,iCAAiC,CAAC;AAEzC,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAmd9C,CAAC"}
|