anteriority-ui 1.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.
- package/.github/workflows/ci.yml +31 -0
- package/.github/workflows/publish.yml +45 -0
- package/.npmrc.bak +1 -0
- package/.storybook/main.js +15 -0
- package/.storybook/preview.jsx +26 -0
- package/AnteriorityUI.md +2400 -0
- package/CLAUDE.md +91 -0
- package/README.md +182 -0
- package/assets/anteriorityUI/AnteriorityUI.logo.jpeg +0 -0
- package/assets/favicon/anteriorityUI.ico +0 -0
- package/common/api/client.js +43 -0
- package/common/storage/LocalStorage.js +13 -0
- package/common/styles/typography.css +5 -0
- package/common/styles/variables.css +192 -0
- package/common/theme/muiTheme.js +9 -0
- package/features/password-reset/api.js +39 -0
- package/features/user-profile/api.js +5 -0
- package/hooks/useAdminPasswordReset.js +133 -0
- package/index.js +57 -0
- package/package.json +57 -0
- package/pnpm-workspace.yaml +3 -0
- package/screens/components/AlertModal/AlertModal.jsx +259 -0
- package/screens/components/AlertModal/AlertModal.module.css +185 -0
- package/screens/components/AlertModal/AlertModal.stories.jsx +87 -0
- package/screens/components/Avatar/index.jsx +0 -0
- package/screens/components/Avatar/index.module.css +0 -0
- package/screens/components/Avatar/utils.js +0 -0
- package/screens/components/Badge/index.jsx +33 -0
- package/screens/components/Badge/index.module.css +18 -0
- package/screens/components/Badge/index.stories.jsx +40 -0
- package/screens/components/Barnner/index.jsx +21 -0
- package/screens/components/Barnner/index.module.css +33 -0
- package/screens/components/Barnner/index.stories.jsx +39 -0
- package/screens/components/Barnner/utils.js +0 -0
- package/screens/components/BlueLink/index.jsx +27 -0
- package/screens/components/BlueLink/index.module.css +11 -0
- package/screens/components/BlueLink/index.stories.jsx +29 -0
- package/screens/components/Breadcrumbs/index.jsx +62 -0
- package/screens/components/Breadcrumbs/index.module.css +158 -0
- package/screens/components/Breadcrumbs/index.stories.jsx +37 -0
- package/screens/components/Button/index.jsx +169 -0
- package/screens/components/Button/index.module.css +168 -0
- package/screens/components/Button/index.stories.jsx +71 -0
- package/screens/components/Button/utils.js +28 -0
- package/screens/components/CalendarComponent/CustomDatePicker.jsx +248 -0
- package/screens/components/CalendarComponent/CustomDatePicker.module.css +323 -0
- package/screens/components/CalendarComponent/CustomDatePicker.stories.jsx +45 -0
- package/screens/components/CalendarPicker/Constants.js +12 -0
- package/screens/components/CalendarPicker/index.jsx +263 -0
- package/screens/components/CalendarPicker/index.module.css +147 -0
- package/screens/components/CalendarPicker/index.stories.jsx +45 -0
- package/screens/components/CalendarPicker/utils.js +42 -0
- package/screens/components/CardV1/index.jsx +165 -0
- package/screens/components/CardV1/index.module.css +232 -0
- package/screens/components/CardV1/index.stories.jsx +62 -0
- package/screens/components/CardV1/utils.js +49 -0
- package/screens/components/ChatWindow/index.jsx +251 -0
- package/screens/components/ChatWindow/index.module.css +311 -0
- package/screens/components/ChatWindow/index.stories.jsx +62 -0
- package/screens/components/Checks/index.jsx +31 -0
- package/screens/components/Checks/index.module.css +32 -0
- package/screens/components/Checks/index.stories.jsx +32 -0
- package/screens/components/Container/index.jsx +36 -0
- package/screens/components/Container/index.module.css +24 -0
- package/screens/components/Container/index.stories.jsx +32 -0
- package/screens/components/CopyText/index.jsx +42 -0
- package/screens/components/CopyText/index.module.css +52 -0
- package/screens/components/CopyText/index.stories.jsx +24 -0
- package/screens/components/CountdownBar/constants.js +3 -0
- package/screens/components/CountdownBar/index.jsx +81 -0
- package/screens/components/CountdownBar/index.module.css +45 -0
- package/screens/components/CountdownBar/index.stories.jsx +43 -0
- package/screens/components/CountdownBar/utils.js +119 -0
- package/screens/components/DateTag/index.jsx +33 -0
- package/screens/components/DateTag/index.module.css +12 -0
- package/screens/components/DateTag/index.stories.jsx +29 -0
- package/screens/components/DesplegablePanel/constants.js +0 -0
- package/screens/components/DesplegablePanel/index.jsx +61 -0
- package/screens/components/DesplegablePanel/index.module.css +120 -0
- package/screens/components/DesplegablePanel/index.stories.jsx +44 -0
- package/screens/components/DesplegablePanel/utils.js +0 -0
- package/screens/components/DrawPanel/index.jsx +217 -0
- package/screens/components/DrawPanel/index.module.css +252 -0
- package/screens/components/DrawPanel/index.stories.jsx +66 -0
- package/screens/components/DrawPanel/utils.js +0 -0
- package/screens/components/Filter/index.jsx +105 -0
- package/screens/components/Filter/index.module.css +91 -0
- package/screens/components/Filter/index.stories.jsx +46 -0
- package/screens/components/Filter/utils.js +0 -0
- package/screens/components/FormControls/FormControls.module.css +86 -0
- package/screens/components/FormControls/index.jsx +51 -0
- package/screens/components/FormControls/index.stories.jsx +36 -0
- package/screens/components/Frame/index.jsx +54 -0
- package/screens/components/Frame/index.module.css +102 -0
- package/screens/components/Frame/index.stories.jsx +37 -0
- package/screens/components/Frame/utils.js +0 -0
- package/screens/components/GreenHighlight/index.jsx +11 -0
- package/screens/components/GreenHighlight/index.module.css +7 -0
- package/screens/components/GreenHighlight/index.stories.jsx +26 -0
- package/screens/components/GreenHighlight/utils.jsx +45 -0
- package/screens/components/HoursPicker/Constants.js +26 -0
- package/screens/components/HoursPicker/index.jsx +350 -0
- package/screens/components/HoursPicker/index.module.css +99 -0
- package/screens/components/HoursPicker/index.stories.jsx +44 -0
- package/screens/components/HoursPicker/utils.js +48 -0
- package/screens/components/InfoTooltip/index.jsx +59 -0
- package/screens/components/InfoTooltip/index.module.css +98 -0
- package/screens/components/InfoTooltip/index.stories.jsx +35 -0
- package/screens/components/Input/index.jsx +36 -0
- package/screens/components/Input/index.module.css +49 -0
- package/screens/components/Input/index.stories.jsx +37 -0
- package/screens/components/Input/utils.js +0 -0
- package/screens/components/Loading/index.jsx +76 -0
- package/screens/components/Loading/index.module.css +193 -0
- package/screens/components/Loading/index.stories.jsx +38 -0
- package/screens/components/Loading/utils.js +0 -0
- package/screens/components/MarkdownContent/index.jsx +16 -0
- package/screens/components/MarkdownContent/index.module.css +149 -0
- package/screens/components/MarkdownContent/index.stories.jsx +30 -0
- package/screens/components/MarkdownEditor/index.jsx +430 -0
- package/screens/components/MarkdownEditor/index.module.css +192 -0
- package/screens/components/MarkdownEditor/index.stories.jsx +50 -0
- package/screens/components/Material-UI/Components/InputWithIcon/index.jsx +87 -0
- package/screens/components/Material-UI/Components/InputWithIcon/index.stories.jsx +49 -0
- package/screens/components/Material-UI/Components/MenuPopover/index.jsx +117 -0
- package/screens/components/Material-UI/Components/MenuPopover/index.stories.jsx +36 -0
- package/screens/components/Material-UI/Components/MultilinePlaceholder/index.jsx +44 -0
- package/screens/components/Material-UI/Components/MultilinePlaceholder/index.stories.jsx +45 -0
- package/screens/components/Material-UI/Components/Paginador/index.jsx +79 -0
- package/screens/components/Material-UI/Components/Paginador/index.stories.jsx +49 -0
- package/screens/components/Material-UI/Components/Search/index.jsx +81 -0
- package/screens/components/Material-UI/Components/Search/index.stories.jsx +68 -0
- package/screens/components/Material-UI/Components/Selector/index.jsx +100 -0
- package/screens/components/Material-UI/Components/Selector/index.module.css +0 -0
- package/screens/components/Material-UI/Components/Selector/index.stories.jsx +52 -0
- package/screens/components/Material-UI/Components/Selector/utils.js +0 -0
- package/screens/components/Material-UI/Components/TextField/index.jsx +61 -0
- package/screens/components/Material-UI/Components/TextField/index.stories.jsx +53 -0
- package/screens/components/ModalTooltip/ModalTooltip.jsx +122 -0
- package/screens/components/ModalTooltip/ModalTooltip.module.css +65 -0
- package/screens/components/ModalTooltip/ModalTooltip.stories.jsx +39 -0
- package/screens/components/Notification/Error/ErrorMessage.jsx +30 -0
- package/screens/components/Notification/Error/ErrorMessage.module.css +57 -0
- package/screens/components/Notification/Error/ErrorMessage.stories.jsx +37 -0
- package/screens/components/PasswordResetPanel/index.jsx +325 -0
- package/screens/components/PasswordResetPanel/index.stories.jsx +26 -0
- package/screens/components/PlaceholderButton/index.jsx +169 -0
- package/screens/components/PlaceholderButton/index.module.css +162 -0
- package/screens/components/PlaceholderButton/index.stories.jsx +69 -0
- package/screens/components/PlaceholderButton/utils.js +42 -0
- package/screens/components/Profile/Avatar/index.jsx +125 -0
- package/screens/components/Profile/Avatar/index.module.css +86 -0
- package/screens/components/Profile/Avatar/index.stories.jsx +48 -0
- package/screens/components/Profile/Avatar/utils.js +18 -0
- package/screens/components/Profile/index.jsx +58 -0
- package/screens/components/Profile/index.module.css +0 -0
- package/screens/components/Profile/index.stories.jsx +38 -0
- package/screens/components/Profile/utils.js +0 -0
- package/screens/components/ScrollBar/index.jsx +62 -0
- package/screens/components/ScrollBar/index.module.css +78 -0
- package/screens/components/ScrollBar/index.stories.jsx +64 -0
- package/screens/components/ScrollBar/utils.js +127 -0
- package/screens/components/Sidebar/constants.js +16 -0
- package/screens/components/Sidebar/index.jsx +399 -0
- package/screens/components/Sidebar/index.module.css +405 -0
- package/screens/components/Sidebar/index.stories.jsx +86 -0
- package/screens/components/Sidebar/utils.js +75 -0
- package/screens/components/Skeleton/index.jsx +11 -0
- package/screens/components/Skeleton/index.module.css +26 -0
- package/screens/components/Skeleton/index.stories.jsx +42 -0
- package/screens/components/SubSidebarLayout/index.jsx +44 -0
- package/screens/components/SubSidebarLayout/index.module.css +80 -0
- package/screens/components/SubSidebarLayout/index.stories.jsx +51 -0
- package/screens/components/SummaryCard/index.jsx +50 -0
- package/screens/components/SummaryCard/index.module.css +30 -0
- package/screens/components/SummaryCard/index.stories.jsx +29 -0
- package/screens/components/Swich/constants.js +4 -0
- package/screens/components/Swich/index.jsx +85 -0
- package/screens/components/Swich/index.module.css +68 -0
- package/screens/components/Swich/index.stories.jsx +44 -0
- package/screens/components/Swich/utils.js +0 -0
- package/screens/components/TableA/index.jsx +156 -0
- package/screens/components/TableA/index.module.css +105 -0
- package/screens/components/TableA/index.stories.jsx +116 -0
- package/screens/components/TableA/utils.js +11 -0
- package/screens/components/TableB/index.jsx +222 -0
- package/screens/components/TableB/index.module.css +295 -0
- package/screens/components/TableB/index.stories.jsx +110 -0
- package/screens/components/TableB/utils.js +11 -0
- package/screens/components/ToggleCard/index.jsx +64 -0
- package/screens/components/ToggleCard/index.module.css +111 -0
- package/screens/components/ToggleCard/index.stories.jsx +49 -0
- package/screens/components/UserEditPopover/index.jsx +102 -0
- package/screens/components/UserEditPopover/index.module.css +97 -0
- package/screens/components/UserEditPopover/index.stories.jsx +49 -0
- package/scripts/build.mjs +129 -0
- package/scripts/check-case.mjs +127 -0
- package/scripts/verify-dist.mjs +45 -0
- package/vitest.config.js +36 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import Paginador from './index';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/Material-UI/Paginador',
|
|
6
|
+
component: Paginador,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const ControlledTemplate = (args) => {
|
|
10
|
+
const [page, setPage] = useState(args.page || 1);
|
|
11
|
+
const [pageSize, setPageSize] = useState(args.pageSize);
|
|
12
|
+
return (
|
|
13
|
+
<Paginador
|
|
14
|
+
{...args}
|
|
15
|
+
page={page}
|
|
16
|
+
onChange={(e, value) => setPage(value)}
|
|
17
|
+
pageSize={pageSize}
|
|
18
|
+
onPageSizeChange={args.onPageSizeChange && setPageSize}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const Default = {
|
|
24
|
+
render: (args) => <ControlledTemplate {...args} />,
|
|
25
|
+
args: {
|
|
26
|
+
count: 10,
|
|
27
|
+
page: 1,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const WithPageSizeSelector = {
|
|
32
|
+
render: (args) => <ControlledTemplate {...args} />,
|
|
33
|
+
args: {
|
|
34
|
+
count: 15,
|
|
35
|
+
page: 2,
|
|
36
|
+
pageSize: 10,
|
|
37
|
+
pageSizeOptions: [5, 10, 20, 50],
|
|
38
|
+
onPageSizeChange: () => {},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const Disabled = {
|
|
43
|
+
render: (args) => <ControlledTemplate {...args} />,
|
|
44
|
+
args: {
|
|
45
|
+
count: 10,
|
|
46
|
+
page: 3,
|
|
47
|
+
disabled: true,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import TextField from '@mui/material/TextField';
|
|
3
|
+
import Autocomplete from '@mui/material/Autocomplete';
|
|
4
|
+
import CircularProgress from '@mui/material/CircularProgress';
|
|
5
|
+
|
|
6
|
+
export default function Search({
|
|
7
|
+
open,
|
|
8
|
+
onOpen,
|
|
9
|
+
onClose,
|
|
10
|
+
options = [],
|
|
11
|
+
loading = false,
|
|
12
|
+
value,
|
|
13
|
+
onChange,
|
|
14
|
+
inputValue,
|
|
15
|
+
onInputChange,
|
|
16
|
+
getOptionLabel = (option) => option?.label || "",
|
|
17
|
+
isOptionEqualToValue = (option, val) => option?.value === val?.value,
|
|
18
|
+
label = "Buscar",
|
|
19
|
+
placeholder = "Buscar...",
|
|
20
|
+
freeSolo = false,
|
|
21
|
+
...props
|
|
22
|
+
}) {
|
|
23
|
+
// Fallback to plain TextField if we are just doing local free text search without options
|
|
24
|
+
if (freeSolo && options.length === 0) {
|
|
25
|
+
return (
|
|
26
|
+
<TextField
|
|
27
|
+
value={value}
|
|
28
|
+
onChange={(e) => {
|
|
29
|
+
if (onChange) onChange(e.target.value);
|
|
30
|
+
}}
|
|
31
|
+
label={label}
|
|
32
|
+
placeholder={placeholder}
|
|
33
|
+
size="small"
|
|
34
|
+
fullWidth
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Autocomplete
|
|
42
|
+
fullWidth
|
|
43
|
+
open={open}
|
|
44
|
+
onOpen={onOpen}
|
|
45
|
+
onClose={onClose}
|
|
46
|
+
value={value}
|
|
47
|
+
onChange={(event, newValue) => {
|
|
48
|
+
if (onChange) onChange(newValue);
|
|
49
|
+
}}
|
|
50
|
+
inputValue={inputValue}
|
|
51
|
+
onInputChange={(event, newInputValue) => {
|
|
52
|
+
if (onInputChange) onInputChange(newInputValue);
|
|
53
|
+
}}
|
|
54
|
+
isOptionEqualToValue={isOptionEqualToValue}
|
|
55
|
+
getOptionLabel={getOptionLabel}
|
|
56
|
+
options={options}
|
|
57
|
+
loading={loading}
|
|
58
|
+
renderInput={(params) => (
|
|
59
|
+
<TextField
|
|
60
|
+
{...params}
|
|
61
|
+
label={label}
|
|
62
|
+
placeholder={placeholder}
|
|
63
|
+
size="small"
|
|
64
|
+
slotProps={{
|
|
65
|
+
...params.slotProps,
|
|
66
|
+
input: {
|
|
67
|
+
...params.slotProps?.input,
|
|
68
|
+
endAdornment: (
|
|
69
|
+
<React.Fragment>
|
|
70
|
+
{loading ? <CircularProgress color="inherit" size={20} /> : null}
|
|
71
|
+
{params.slotProps?.input?.endAdornment}
|
|
72
|
+
</React.Fragment>
|
|
73
|
+
),
|
|
74
|
+
},
|
|
75
|
+
}}
|
|
76
|
+
/>
|
|
77
|
+
)}
|
|
78
|
+
{...props}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import Search from './index';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/Material-UI/Search',
|
|
6
|
+
component: Search,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const options = [
|
|
10
|
+
{ label: 'Ana Gomez', value: 1 },
|
|
11
|
+
{ label: 'Luis Perez', value: 2 },
|
|
12
|
+
{ label: 'Marta Ruiz', value: 3 },
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export const WithOptions = {
|
|
16
|
+
render: (args) => {
|
|
17
|
+
const [value, setValue] = useState(null);
|
|
18
|
+
const [inputValue, setInputValue] = useState('');
|
|
19
|
+
return (
|
|
20
|
+
<Search
|
|
21
|
+
{...args}
|
|
22
|
+
value={value}
|
|
23
|
+
onChange={setValue}
|
|
24
|
+
inputValue={inputValue}
|
|
25
|
+
onInputChange={setInputValue}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
},
|
|
29
|
+
args: {
|
|
30
|
+
options,
|
|
31
|
+
label: 'Buscar usuario',
|
|
32
|
+
placeholder: 'Escribe un nombre...',
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const Loading = {
|
|
37
|
+
render: (args) => {
|
|
38
|
+
const [value, setValue] = useState(null);
|
|
39
|
+
const [inputValue, setInputValue] = useState('');
|
|
40
|
+
return (
|
|
41
|
+
<Search
|
|
42
|
+
{...args}
|
|
43
|
+
value={value}
|
|
44
|
+
onChange={setValue}
|
|
45
|
+
inputValue={inputValue}
|
|
46
|
+
onInputChange={setInputValue}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
},
|
|
50
|
+
args: {
|
|
51
|
+
options: [],
|
|
52
|
+
loading: true,
|
|
53
|
+
label: 'Buscar usuario',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const FreeSolo = {
|
|
58
|
+
render: (args) => {
|
|
59
|
+
const [value, setValue] = useState('');
|
|
60
|
+
return <Search {...args} value={value} onChange={setValue} />;
|
|
61
|
+
},
|
|
62
|
+
args: {
|
|
63
|
+
freeSolo: true,
|
|
64
|
+
options: [],
|
|
65
|
+
label: 'Buscar',
|
|
66
|
+
placeholder: 'Escribe texto libre...',
|
|
67
|
+
},
|
|
68
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import Box from '@mui/material/Box';
|
|
3
|
+
import TextField from '@mui/material/TextField';
|
|
4
|
+
import Autocomplete from '@mui/material/Autocomplete';
|
|
5
|
+
|
|
6
|
+
export default function Selector({
|
|
7
|
+
label,
|
|
8
|
+
value,
|
|
9
|
+
onChange,
|
|
10
|
+
options = [],
|
|
11
|
+
id = "custom-autocomplete",
|
|
12
|
+
style = {},
|
|
13
|
+
className = "",
|
|
14
|
+
fullWidth = true,
|
|
15
|
+
placeholder,
|
|
16
|
+
required,
|
|
17
|
+
requiredColor = "red",
|
|
18
|
+
disableClearable = false
|
|
19
|
+
}) {
|
|
20
|
+
const normalizeVal = (val) => String(val || '').toLowerCase().replace(/[_\s\/-]+/g, '');
|
|
21
|
+
|
|
22
|
+
const selectedOption = (value !== "" && value !== undefined && value !== null)
|
|
23
|
+
? options.find(opt =>
|
|
24
|
+
String(opt.value) === String(value) ||
|
|
25
|
+
normalizeVal(opt.value) === normalizeVal(value) ||
|
|
26
|
+
normalizeVal(opt.label) === normalizeVal(value)
|
|
27
|
+
) || null
|
|
28
|
+
: null;
|
|
29
|
+
|
|
30
|
+
const displayLabel = label ? (
|
|
31
|
+
<span>
|
|
32
|
+
{label}
|
|
33
|
+
{required && <span style={{ color: requiredColor, marginLeft: '4px' }}>**</span>}
|
|
34
|
+
</span>
|
|
35
|
+
) : undefined;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Autocomplete
|
|
39
|
+
id={id}
|
|
40
|
+
sx={{ width: fullWidth ? '100%' : 300, m: 0, ...style }}
|
|
41
|
+
className={className}
|
|
42
|
+
options={options}
|
|
43
|
+
autoHighlight
|
|
44
|
+
openOnFocus
|
|
45
|
+
disableClearable={disableClearable}
|
|
46
|
+
getOptionLabel={(option) => option.label || ""}
|
|
47
|
+
value={selectedOption}
|
|
48
|
+
onChange={(event, newValue) => {
|
|
49
|
+
onChange({ target: { value: newValue ? newValue.value : "" } });
|
|
50
|
+
}}
|
|
51
|
+
isOptionEqualToValue={(option, val) =>
|
|
52
|
+
String(option.value) === String(val?.value) ||
|
|
53
|
+
normalizeVal(option.value) === normalizeVal(val?.value) ||
|
|
54
|
+
normalizeVal(option.label) === normalizeVal(val?.label)
|
|
55
|
+
}
|
|
56
|
+
slotProps={{
|
|
57
|
+
popper: {
|
|
58
|
+
sx: { zIndex: 100000 }
|
|
59
|
+
}
|
|
60
|
+
}}
|
|
61
|
+
renderOption={(props, option) => {
|
|
62
|
+
const { key, ...optionProps } = props;
|
|
63
|
+
return (
|
|
64
|
+
<Box
|
|
65
|
+
key={key}
|
|
66
|
+
component="li"
|
|
67
|
+
sx={{ display: 'flex', alignItems: 'center', gap: '8px', ...optionProps.sx }}
|
|
68
|
+
{...optionProps}
|
|
69
|
+
>
|
|
70
|
+
{option.icon && <img src={option.icon} alt="" style={{ width: 24, height: 24, objectFit: 'contain' }} />}
|
|
71
|
+
{option.label}
|
|
72
|
+
</Box>
|
|
73
|
+
);
|
|
74
|
+
}}
|
|
75
|
+
renderInput={(params) => (
|
|
76
|
+
<TextField
|
|
77
|
+
{...params}
|
|
78
|
+
label={displayLabel}
|
|
79
|
+
placeholder={placeholder}
|
|
80
|
+
size="small"
|
|
81
|
+
inputProps={{
|
|
82
|
+
...params.inputProps,
|
|
83
|
+
autoComplete: 'off',
|
|
84
|
+
form: {
|
|
85
|
+
autocomplete: 'off',
|
|
86
|
+
},
|
|
87
|
+
}}
|
|
88
|
+
slotProps={{
|
|
89
|
+
...params.slotProps,
|
|
90
|
+
htmlInput: {
|
|
91
|
+
...params.slotProps?.htmlInput,
|
|
92
|
+
autoComplete: 'off',
|
|
93
|
+
name: 'no-autofill-' + Math.random(),
|
|
94
|
+
},
|
|
95
|
+
}}
|
|
96
|
+
/>
|
|
97
|
+
)}
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import Selector from './index';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/Material-UI/Selector',
|
|
6
|
+
component: Selector,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const options = [
|
|
10
|
+
{ value: 'perro', label: 'Perro' },
|
|
11
|
+
{ value: 'gato', label: 'Gato' },
|
|
12
|
+
{ value: 'ave', label: 'Ave' },
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const ControlledTemplate = (args) => {
|
|
16
|
+
const [value, setValue] = useState(args.value || '');
|
|
17
|
+
return (
|
|
18
|
+
<Selector
|
|
19
|
+
{...args}
|
|
20
|
+
value={value}
|
|
21
|
+
onChange={(e) => setValue(e.target.value)}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const Default = {
|
|
27
|
+
render: (args) => <ControlledTemplate {...args} />,
|
|
28
|
+
args: {
|
|
29
|
+
label: 'Especie',
|
|
30
|
+
options,
|
|
31
|
+
placeholder: 'Selecciona una especie',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const Required = {
|
|
36
|
+
render: (args) => <ControlledTemplate {...args} />,
|
|
37
|
+
args: {
|
|
38
|
+
label: 'Especie',
|
|
39
|
+
options,
|
|
40
|
+
required: true,
|
|
41
|
+
placeholder: 'Selecciona una especie',
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const WithValue = {
|
|
46
|
+
render: (args) => <ControlledTemplate {...args} />,
|
|
47
|
+
args: {
|
|
48
|
+
label: 'Especie',
|
|
49
|
+
options,
|
|
50
|
+
value: 'gato',
|
|
51
|
+
},
|
|
52
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import MuiTextField from '@mui/material/TextField';
|
|
3
|
+
import { formatHighlightedText } from '../../../GreenHighlight/utils';
|
|
4
|
+
|
|
5
|
+
const TextField = forwardRef(({
|
|
6
|
+
label,
|
|
7
|
+
value,
|
|
8
|
+
onChange,
|
|
9
|
+
error,
|
|
10
|
+
helperText,
|
|
11
|
+
type = "text",
|
|
12
|
+
variant = "outlined",
|
|
13
|
+
size = "small",
|
|
14
|
+
fullWidth = true,
|
|
15
|
+
placeholder,
|
|
16
|
+
required,
|
|
17
|
+
requiredColor = 'red',
|
|
18
|
+
bgColor = '#fff',
|
|
19
|
+
textColor = '#0f172a',
|
|
20
|
+
...props
|
|
21
|
+
}, ref) => {
|
|
22
|
+
const formattedLabel = typeof label === 'string' ? formatHighlightedText(label) : label;
|
|
23
|
+
const displayLabel = formattedLabel ? (
|
|
24
|
+
<span>
|
|
25
|
+
{formattedLabel}
|
|
26
|
+
{required && <span style={{ color: requiredColor, marginLeft: '4px' }}>**</span>}
|
|
27
|
+
</span>
|
|
28
|
+
) : undefined;
|
|
29
|
+
|
|
30
|
+
const displayHelperText = typeof helperText === 'string' ? formatHighlightedText(helperText) : helperText;
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<MuiTextField
|
|
34
|
+
label={displayLabel}
|
|
35
|
+
value={value}
|
|
36
|
+
onChange={onChange}
|
|
37
|
+
error={!!error}
|
|
38
|
+
helperText={error || displayHelperText}
|
|
39
|
+
type={type}
|
|
40
|
+
variant={variant}
|
|
41
|
+
size={size}
|
|
42
|
+
fullWidth={fullWidth}
|
|
43
|
+
placeholder={placeholder}
|
|
44
|
+
sx={{
|
|
45
|
+
m: 0,
|
|
46
|
+
'& .MuiInputBase-root': { backgroundColor: bgColor },
|
|
47
|
+
'& input:-webkit-autofill': {
|
|
48
|
+
WebkitBoxShadow: `0 0 0 1000px ${bgColor} inset`,
|
|
49
|
+
WebkitTextFillColor: textColor,
|
|
50
|
+
caretColor: textColor,
|
|
51
|
+
},
|
|
52
|
+
}}
|
|
53
|
+
inputRef={ref}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
TextField.displayName = 'TextField';
|
|
60
|
+
|
|
61
|
+
export default TextField;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import TextField from './index';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/Material-UI/TextField',
|
|
6
|
+
component: TextField,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const ControlledTemplate = (args) => {
|
|
10
|
+
const [value, setValue] = useState(args.value || '');
|
|
11
|
+
return (
|
|
12
|
+
<TextField
|
|
13
|
+
{...args}
|
|
14
|
+
value={value}
|
|
15
|
+
onChange={(e) => setValue(e.target.value)}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const Default = {
|
|
21
|
+
render: (args) => <ControlledTemplate {...args} />,
|
|
22
|
+
args: {
|
|
23
|
+
label: 'Nombre',
|
|
24
|
+
placeholder: 'Escribe tu nombre...',
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const Required = {
|
|
29
|
+
render: (args) => <ControlledTemplate {...args} />,
|
|
30
|
+
args: {
|
|
31
|
+
label: 'Correo electrónico',
|
|
32
|
+
placeholder: 'usuario@correo.com',
|
|
33
|
+
required: true,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const WithError = {
|
|
38
|
+
render: (args) => <ControlledTemplate {...args} />,
|
|
39
|
+
args: {
|
|
40
|
+
label: 'Contraseña',
|
|
41
|
+
type: 'password',
|
|
42
|
+
error: true,
|
|
43
|
+
helperText: 'La contraseña debe tener al menos 6 caracteres',
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const Disabled = {
|
|
48
|
+
args: {
|
|
49
|
+
label: 'Correo electrónico (Autocompletado)',
|
|
50
|
+
value: 'usuario@correo.com',
|
|
51
|
+
disabled: true,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import React, { useState, useRef, useEffect, useCallback } from "react";
|
|
2
|
+
import { createPortal } from "react-dom";
|
|
3
|
+
import styles from "./ModalTooltip.module.css";
|
|
4
|
+
|
|
5
|
+
const ModalTooltip = ({
|
|
6
|
+
text,
|
|
7
|
+
children,
|
|
8
|
+
position = "top",
|
|
9
|
+
delay = 150,
|
|
10
|
+
style,
|
|
11
|
+
bgColor,
|
|
12
|
+
textColor,
|
|
13
|
+
...props
|
|
14
|
+
}) => {
|
|
15
|
+
const [visible, setVisible] = useState(false);
|
|
16
|
+
const [activePos, setActivePos] = useState(position);
|
|
17
|
+
const [coords, setCoords] = useState({ top: 0, left: 0 });
|
|
18
|
+
|
|
19
|
+
const triggerRef = useRef(null);
|
|
20
|
+
const tooltipRef = useRef(null);
|
|
21
|
+
const timeoutRef = useRef(null);
|
|
22
|
+
|
|
23
|
+
// Cálculo preciso de posición con prevención de colisiones con los bordes del viewport
|
|
24
|
+
const updatePosition = useCallback(() => {
|
|
25
|
+
if (!triggerRef.current) return;
|
|
26
|
+
|
|
27
|
+
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
28
|
+
const gap = 8; // Distancia entre el trigger y el tooltip
|
|
29
|
+
let currentPos = position;
|
|
30
|
+
|
|
31
|
+
// Dimensiones reales del tooltip
|
|
32
|
+
const tooltipWidth = tooltipRef.current ? tooltipRef.current.offsetWidth : 200;
|
|
33
|
+
const tooltipHeight = tooltipRef.current ? tooltipRef.current.offsetHeight : 36;
|
|
34
|
+
|
|
35
|
+
// Inversión automática si colisiona arriba/abajo
|
|
36
|
+
if (position === "top" && triggerRect.top - tooltipHeight - gap < 0) {
|
|
37
|
+
currentPos = "bottom";
|
|
38
|
+
} else if (position === "bottom" && triggerRect.bottom + tooltipHeight + gap > window.innerHeight) {
|
|
39
|
+
currentPos = "top";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setActivePos(currentPos);
|
|
43
|
+
|
|
44
|
+
// Calcular Top
|
|
45
|
+
let top = currentPos === "bottom"
|
|
46
|
+
? triggerRect.bottom + window.scrollY + gap
|
|
47
|
+
: triggerRect.top + window.scrollY - gap;
|
|
48
|
+
|
|
49
|
+
// Calcular Left con clamp para que nunca se salga horizontalmente
|
|
50
|
+
let left = triggerRect.left + window.scrollX + triggerRect.width / 2;
|
|
51
|
+
const minLeft = tooltipWidth / 2 + 10;
|
|
52
|
+
const maxLeft = window.innerWidth - tooltipWidth / 2 - 10;
|
|
53
|
+
left = Math.max(minLeft, Math.min(left, maxLeft));
|
|
54
|
+
|
|
55
|
+
setCoords({ top, left });
|
|
56
|
+
}, [position]);
|
|
57
|
+
|
|
58
|
+
// Listener global de scroll y resize cuando está visible
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (!visible) return;
|
|
61
|
+
|
|
62
|
+
updatePosition();
|
|
63
|
+
|
|
64
|
+
const handleScrollOrResize = () => updatePosition();
|
|
65
|
+
window.addEventListener("scroll", handleScrollOrResize, true);
|
|
66
|
+
window.addEventListener("resize", handleScrollOrResize);
|
|
67
|
+
|
|
68
|
+
return () => {
|
|
69
|
+
window.removeEventListener("scroll", handleScrollOrResize, true);
|
|
70
|
+
window.removeEventListener("resize", handleScrollOrResize);
|
|
71
|
+
};
|
|
72
|
+
}, [visible, updatePosition]);
|
|
73
|
+
|
|
74
|
+
const handleMouseEnter = () => {
|
|
75
|
+
timeoutRef.current = setTimeout(() => {
|
|
76
|
+
setVisible(true);
|
|
77
|
+
}, delay);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const handleMouseLeave = () => {
|
|
81
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
82
|
+
setVisible(false);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<span
|
|
87
|
+
ref={triggerRef}
|
|
88
|
+
className={styles.container}
|
|
89
|
+
onMouseEnter={handleMouseEnter}
|
|
90
|
+
onMouseLeave={handleMouseLeave}
|
|
91
|
+
style={{
|
|
92
|
+
display: "inline-flex",
|
|
93
|
+
alignItems: "center",
|
|
94
|
+
position: "relative",
|
|
95
|
+
...style
|
|
96
|
+
}}
|
|
97
|
+
{...props}
|
|
98
|
+
>
|
|
99
|
+
{children}
|
|
100
|
+
{visible &&
|
|
101
|
+
typeof document !== "undefined" &&
|
|
102
|
+
createPortal(
|
|
103
|
+
<div
|
|
104
|
+
ref={tooltipRef}
|
|
105
|
+
className={`${styles.tooltip} ${styles[activePos]}`}
|
|
106
|
+
style={{
|
|
107
|
+
top: `${coords.top}px`,
|
|
108
|
+
left: `${coords.left}px`,
|
|
109
|
+
...(bgColor ? { '--modaltooltip-bg': bgColor } : {}),
|
|
110
|
+
...(textColor ? { '--modaltooltip-text': textColor } : {}),
|
|
111
|
+
}}
|
|
112
|
+
>
|
|
113
|
+
{text}
|
|
114
|
+
<span className={styles.arrow} />
|
|
115
|
+
</div>,
|
|
116
|
+
document.body
|
|
117
|
+
)}
|
|
118
|
+
</span>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export default ModalTooltip;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
cursor: pointer;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.tooltip {
|
|
6
|
+
position: absolute;
|
|
7
|
+
z-index: 99999;
|
|
8
|
+
width: max-content;
|
|
9
|
+
max-width: 320px;
|
|
10
|
+
background-color: var(--modaltooltip-bg, #0f172a); /* Slate 900 */
|
|
11
|
+
color: var(--modaltooltip-text, #f8fafc);
|
|
12
|
+
padding: 6px 12px;
|
|
13
|
+
border-radius: 8px;
|
|
14
|
+
font-size: 12px;
|
|
15
|
+
font-weight: 500;
|
|
16
|
+
line-height: 1.4;
|
|
17
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.25), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
|
|
18
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
19
|
+
pointer-events: none;
|
|
20
|
+
animation: tooltipFadeIn 0.18s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Posicionamiento y Transformaciones */
|
|
24
|
+
.top {
|
|
25
|
+
transform: translate(-50%, -100%);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.bottom {
|
|
29
|
+
transform: translate(-50%, 0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Flecha direccional */
|
|
33
|
+
.arrow {
|
|
34
|
+
position: absolute;
|
|
35
|
+
width: 8px;
|
|
36
|
+
height: 8px;
|
|
37
|
+
background-color: var(--modaltooltip-bg, #0f172a);
|
|
38
|
+
transform: rotate(45deg);
|
|
39
|
+
left: 50%;
|
|
40
|
+
margin-left: -4px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.top .arrow {
|
|
44
|
+
bottom: -4px;
|
|
45
|
+
border-right: 1px solid rgba(255, 255, 255, 0.1);
|
|
46
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.bottom .arrow {
|
|
50
|
+
top: -4px;
|
|
51
|
+
border-left: 1px solid rgba(255, 255, 255, 0.1);
|
|
52
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Animación de entrada con Scale suave */
|
|
56
|
+
@keyframes tooltipFadeIn {
|
|
57
|
+
from {
|
|
58
|
+
opacity: 0;
|
|
59
|
+
scale: 0.92;
|
|
60
|
+
}
|
|
61
|
+
to {
|
|
62
|
+
opacity: 1;
|
|
63
|
+
scale: 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import ModalTooltip from './ModalTooltip';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
title: 'Components/ModalTooltip',
|
|
5
|
+
component: ModalTooltip,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const Top = {
|
|
9
|
+
args: {
|
|
10
|
+
text: 'Tooltip on top',
|
|
11
|
+
position: 'top',
|
|
12
|
+
children: <button type="button">Hover me</button>,
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const Bottom = {
|
|
17
|
+
args: {
|
|
18
|
+
text: 'Tooltip on bottom',
|
|
19
|
+
position: 'bottom',
|
|
20
|
+
children: <button type="button">Hover me</button>,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const WithDelay = {
|
|
25
|
+
args: {
|
|
26
|
+
text: 'Shows after a longer delay',
|
|
27
|
+
position: 'top',
|
|
28
|
+
delay: 600,
|
|
29
|
+
children: <button type="button">Slow tooltip</button>,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const OnText = {
|
|
34
|
+
args: {
|
|
35
|
+
text: 'More information about this label',
|
|
36
|
+
position: 'right',
|
|
37
|
+
children: <span style={{ textDecoration: 'underline dotted' }}>Hover this text</span>,
|
|
38
|
+
},
|
|
39
|
+
};
|