groovinads-ui 1.2.69 → 1.2.70
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/README.md +127 -68
- package/dist/index.es.js +3 -3
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/src/components/Dropdowns/DropdownMultiSelect.jsx +54 -14
- package/src/components/Navigation/Sidebar.jsx +48 -22
- package/src/stories/DropdownMultiSelect.stories.jsx +17 -27
- package/src/stories/Sidebar.stories.jsx +31 -6
- package/version.js +8 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "groovinads-ui",
|
|
3
3
|
"description": "Groovinads UI is a React component library designed exclusively for Groovinads applications. It provides ready-to-use UI elements styled according to Groovinads design guidelines to facilitate rapid development.",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.70",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"css",
|
|
7
7
|
"sass",
|
|
@@ -18,6 +18,7 @@ const DropdownMultiSelect = ({
|
|
|
18
18
|
inputLabel = '',
|
|
19
19
|
object = false,
|
|
20
20
|
nameKey,
|
|
21
|
+
customKey,
|
|
21
22
|
idKey,
|
|
22
23
|
searchLabel = 'Search',
|
|
23
24
|
onToggle,
|
|
@@ -43,6 +44,8 @@ const DropdownMultiSelect = ({
|
|
|
43
44
|
const [innerShow, setInnerShow] = useState(!!show);
|
|
44
45
|
|
|
45
46
|
const dropdownRef = useRef(null);
|
|
47
|
+
const toggleRef = useRef(null);
|
|
48
|
+
const menuRef = useRef(null);
|
|
46
49
|
|
|
47
50
|
const { highlightText } = useTextFormatter();
|
|
48
51
|
|
|
@@ -73,14 +76,13 @@ const DropdownMultiSelect = ({
|
|
|
73
76
|
|
|
74
77
|
const valuesFromSearch = () =>
|
|
75
78
|
values.filter(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
(item) =>
|
|
80
|
+
(object ? `${item[idKey]} ${item[nameKey]} ${item[customKey]}` : item)
|
|
81
|
+
.toLowerCase()
|
|
82
|
+
.includes(query.toLowerCase()) &&
|
|
83
|
+
(showStatus ? parseInt(item.status) === parseInt(showStatus) : true),
|
|
84
|
+
);
|
|
82
85
|
|
|
83
|
-
|
|
84
86
|
const handleClickOutside = useCallback((event) => {
|
|
85
87
|
if (
|
|
86
88
|
dropdownRef?.current &&
|
|
@@ -91,7 +93,7 @@ const DropdownMultiSelect = ({
|
|
|
91
93
|
setShow(false);
|
|
92
94
|
}
|
|
93
95
|
}, []);
|
|
94
|
-
|
|
96
|
+
|
|
95
97
|
// VALIDATION REQUIRED
|
|
96
98
|
const validateRequired = () => {
|
|
97
99
|
if (!valuesSelected.length) {
|
|
@@ -100,11 +102,11 @@ const DropdownMultiSelect = ({
|
|
|
100
102
|
}, 2000);
|
|
101
103
|
}
|
|
102
104
|
};
|
|
103
|
-
|
|
105
|
+
|
|
104
106
|
useEffect(() => {
|
|
105
107
|
setInnerShow(show);
|
|
106
108
|
}, [show]);
|
|
107
|
-
|
|
109
|
+
|
|
108
110
|
useEffect(() => {
|
|
109
111
|
document.addEventListener('click', handleClickOutside);
|
|
110
112
|
return () => {
|
|
@@ -115,6 +117,33 @@ const DropdownMultiSelect = ({
|
|
|
115
117
|
useEffect(() => {
|
|
116
118
|
if (validate && errorRequired) validateRequired();
|
|
117
119
|
}, [validate, errorRequired]);
|
|
120
|
+
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (overflow && menuRef.current && toggleRef.current) {
|
|
123
|
+
menuRef.current.style.width = `${toggleRef.current.offsetWidth}px`;
|
|
124
|
+
}
|
|
125
|
+
}, [innerShow, overflow]);
|
|
126
|
+
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
function updateMenuWidth() {
|
|
129
|
+
if (overflow && menuRef.current && toggleRef.current) {
|
|
130
|
+
const width = toggleRef.current.offsetWidth;
|
|
131
|
+
menuRef.current.style.width = `${width}px`;
|
|
132
|
+
menuRef.current.style.minWidth = `${width}px`;
|
|
133
|
+
menuRef.current.style.maxWidth = `${width}px`;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (innerShow) {
|
|
138
|
+
updateMenuWidth();
|
|
139
|
+
window.addEventListener('resize', updateMenuWidth);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return () => {
|
|
143
|
+
window.removeEventListener('resize', updateMenuWidth);
|
|
144
|
+
};
|
|
145
|
+
}, [innerShow, overflow]);
|
|
146
|
+
|
|
118
147
|
return (
|
|
119
148
|
<Dropdown
|
|
120
149
|
className={className}
|
|
@@ -127,7 +156,8 @@ const DropdownMultiSelect = ({
|
|
|
127
156
|
>
|
|
128
157
|
<Dropdown.Toggle
|
|
129
158
|
as={'div'}
|
|
130
|
-
|
|
159
|
+
ref={toggleRef}
|
|
160
|
+
className={`btn btn-${buttonVariant} ${nowrap ? 'nowrap' : ''}${errorRequired && valuesSelected.length === 0 ? 'not-validated' : ''}`}
|
|
131
161
|
onClick={(e) => {
|
|
132
162
|
e.stopPropagation(); // Detiene la propagación del clic
|
|
133
163
|
setInnerShow((prevShow) => !prevShow); // Alterna el estado interno del dropdown
|
|
@@ -147,8 +177,14 @@ const DropdownMultiSelect = ({
|
|
|
147
177
|
}}
|
|
148
178
|
key={'Dropdown.PillComponent' + index}
|
|
149
179
|
>
|
|
150
|
-
{
|
|
151
|
-
|
|
180
|
+
{customKey
|
|
181
|
+
? `${value[nameKey]} - ${value[customKey]}`
|
|
182
|
+
: idInPill
|
|
183
|
+
? `#${value[idKey]}`
|
|
184
|
+
: value[nameKey] || value}
|
|
185
|
+
|
|
186
|
+
{/* {idInPill ? `#${value[idKey]} - ` : ''}
|
|
187
|
+
<span>{object ? value[nameKey] : value}</span> */}
|
|
152
188
|
</PillComponent>
|
|
153
189
|
);
|
|
154
190
|
})}
|
|
@@ -165,6 +201,7 @@ const DropdownMultiSelect = ({
|
|
|
165
201
|
|
|
166
202
|
<Dropdown.Menu
|
|
167
203
|
className='w-100'
|
|
204
|
+
ref={menuRef}
|
|
168
205
|
popperConfig={
|
|
169
206
|
overflow
|
|
170
207
|
? {
|
|
@@ -208,7 +245,9 @@ const DropdownMultiSelect = ({
|
|
|
208
245
|
>
|
|
209
246
|
{highlightText(
|
|
210
247
|
object
|
|
211
|
-
?
|
|
248
|
+
? customKey
|
|
249
|
+
? `${value[nameKey]} - ${value[customKey]}`
|
|
250
|
+
: `${hasId ? `#${value[idKey]} - ` : ''}${value[nameKey]}`
|
|
212
251
|
: value[nameKey] || value,
|
|
213
252
|
query,
|
|
214
253
|
)}
|
|
@@ -242,6 +281,7 @@ DropdownMultiSelect.propTypes = {
|
|
|
242
281
|
setShow: PropTypes.func,
|
|
243
282
|
object: PropTypes.bool,
|
|
244
283
|
nameKey: PropTypes.string,
|
|
284
|
+
customKey: PropTypes.string,
|
|
245
285
|
idKey: PropTypes.string,
|
|
246
286
|
idInPill: PropTypes.bool,
|
|
247
287
|
showStatus: PropTypes.string,
|
|
@@ -25,7 +25,9 @@ const Sidebar = ({
|
|
|
25
25
|
inModal = false,
|
|
26
26
|
customUrl,
|
|
27
27
|
}) => {
|
|
28
|
-
const isMobile = inModal
|
|
28
|
+
const isMobile = inModal
|
|
29
|
+
? true
|
|
30
|
+
: useMediaQuery({ query: '(max-width: 992px)' });
|
|
29
31
|
|
|
30
32
|
const url = customUrl !== undefined ? customUrl : window.location.pathname; // to get current url
|
|
31
33
|
|
|
@@ -55,7 +57,8 @@ const Sidebar = ({
|
|
|
55
57
|
|
|
56
58
|
useEffect(() => {
|
|
57
59
|
if (isMobile && setShow && !inModal) setShow(innerShow);
|
|
58
|
-
if (!inModal)
|
|
60
|
+
if (!inModal)
|
|
61
|
+
setInnerShow(isMobile ? false : firstOpen.current ? defaultOpened : show);
|
|
59
62
|
firstOpen.current = false;
|
|
60
63
|
}, []);
|
|
61
64
|
|
|
@@ -80,13 +83,14 @@ const Sidebar = ({
|
|
|
80
83
|
<div className='scroll'>
|
|
81
84
|
{customLinks.map((section, i) => (
|
|
82
85
|
<div className='sidebar-section' key={`sectionIndex${i}`}>
|
|
83
|
-
{section.title ? <h4>{section.title}</h4> : <></>
|
|
86
|
+
{section.title ? <h4>{section.title}</h4> : <></>}
|
|
84
87
|
|
|
85
88
|
{/* PROPS LINKS */}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
|
|
90
|
+
<ul className='nav'>
|
|
91
|
+
{(section.backData ? sidebarLinks : section.links || []).map(
|
|
92
|
+
(linkSection, y) => (
|
|
93
|
+
<li className='nav-item' key={`linksSections${y}`}>
|
|
90
94
|
{/* CHILDREN - If has children, the collapse is expanded */}
|
|
91
95
|
{linkSection.children && linkSection.children.length ? (
|
|
92
96
|
<>
|
|
@@ -121,20 +125,41 @@ const Sidebar = ({
|
|
|
121
125
|
</Collapse>
|
|
122
126
|
</>
|
|
123
127
|
) : (
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
<>
|
|
129
|
+
<button
|
|
130
|
+
className={`nav-link ${
|
|
131
|
+
url === linkSection.url ? 'active' : ''
|
|
132
|
+
}`}
|
|
133
|
+
onClick={() => onNavigate(linkSection.url)}
|
|
134
|
+
>
|
|
135
|
+
<Icon iconName={linkSection.icon} />
|
|
136
|
+
|
|
137
|
+
{linkSection.pendingType ? (
|
|
138
|
+
<div className='link-wrapper'>
|
|
139
|
+
{linkSection.name}
|
|
140
|
+
{linkSection.pendingLength > 0 &&
|
|
141
|
+
(linkSection.pendingType === 'warning' ? (
|
|
142
|
+
<Icon
|
|
143
|
+
iconName='triangle-exclamation'
|
|
144
|
+
className='warning-icon'
|
|
145
|
+
style='duotone'
|
|
146
|
+
/>
|
|
147
|
+
) : linkSection.pendingType === 'badge' ? (
|
|
148
|
+
<span className='badge'>
|
|
149
|
+
{linkSection.pendingLength}
|
|
150
|
+
</span>
|
|
151
|
+
) : null)}
|
|
152
|
+
</div>
|
|
153
|
+
) : (
|
|
154
|
+
linkSection.name
|
|
155
|
+
)}
|
|
156
|
+
</button>
|
|
157
|
+
</>
|
|
133
158
|
)}
|
|
134
159
|
</li>
|
|
135
|
-
|
|
136
|
-
)
|
|
137
|
-
|
|
160
|
+
),
|
|
161
|
+
)}
|
|
162
|
+
</ul>
|
|
138
163
|
</div>
|
|
139
164
|
))}
|
|
140
165
|
</div>
|
|
@@ -160,13 +185,14 @@ Sidebar.propTypes = {
|
|
|
160
185
|
setShow: PropTypes.func, // Add setShow prop for controlling visibility
|
|
161
186
|
onNavigate: PropTypes.func.isRequired, // Nueva prop para manejar la navegación
|
|
162
187
|
selectedClient: PropTypes.object,
|
|
163
|
-
showClients:PropTypes.oneOf([true, false, 'single']),
|
|
188
|
+
showClients: PropTypes.oneOf([true, false, 'single']),
|
|
164
189
|
setGroovinProfile: PropTypes.func,
|
|
165
190
|
inModal: PropTypes.bool,
|
|
166
191
|
customUrl: PropTypes.oneOfType([
|
|
167
192
|
PropTypes.string,
|
|
168
|
-
PropTypes.oneOf([undefined])
|
|
169
|
-
|
|
193
|
+
PropTypes.oneOf([undefined]),
|
|
194
|
+
]),
|
|
195
|
+
pendingType: PropTypes.oneOf(['warning', 'badge']),
|
|
170
196
|
};
|
|
171
197
|
|
|
172
198
|
export default Sidebar;
|
|
@@ -2,8 +2,8 @@ import React, { useState } from 'react';
|
|
|
2
2
|
import DropdownMultiSelect from '../components/Dropdowns/DropdownMultiSelect';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
title: 'Dropdown/DropdownMultiSelect',
|
|
6
|
+
component: DropdownMultiSelect,
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
const Template = (args) => {
|
|
@@ -15,12 +15,12 @@ const Template = (args) => {
|
|
|
15
15
|
/* ========== */
|
|
16
16
|
/* OPCION 1 - Opciones y valores seleccionados son array de objetos */
|
|
17
17
|
const filters = [
|
|
18
|
-
{ id: 1, name: 'Filter 1', showStatus: '1' },
|
|
19
|
-
{ id: 2, name: 'Filter 2', showStatus: '0' },
|
|
20
|
-
{ id: 3, name: 'Filter 3', showStatus: '1' },
|
|
21
|
-
{ id: 4, name: 'Filter 4', showStatus: '0' },
|
|
22
|
-
{ id: 5, name: 'Filter 5', showStatus: '0' },
|
|
23
|
-
{ id: 6, name: 'Filter 6', showStatus: '2' },
|
|
18
|
+
{ id: 1, name: 'Filter 1', showStatus: '1', name1: 'loreal' },
|
|
19
|
+
{ id: 2, name: 'Filter 2', showStatus: '0', name1: 'jabon' },
|
|
20
|
+
{ id: 3, name: 'Filter 3', showStatus: '1', name1: 'blue' },
|
|
21
|
+
{ id: 4, name: 'Filter 4', showStatus: '0', name1: 'name' },
|
|
22
|
+
{ id: 5, name: 'Filter 5', showStatus: '0', name1: 'name' },
|
|
23
|
+
{ id: 6, name: 'Filter 6', showStatus: '2', name1: 'name' },
|
|
24
24
|
];
|
|
25
25
|
const [selectedValues, setSelectedValues] = useState([]);
|
|
26
26
|
/* ========== */
|
|
@@ -35,11 +35,12 @@ const Template = (args) => {
|
|
|
35
35
|
'Filter 5',
|
|
36
36
|
];
|
|
37
37
|
const [selectedStringValues, setSelectedStringValues] = useState([]);
|
|
38
|
+
|
|
39
|
+
/* const list= ['palabra1', 'palabra2'] */
|
|
38
40
|
/* =========== */
|
|
39
41
|
|
|
40
42
|
return (
|
|
41
43
|
<>
|
|
42
|
-
{/* OPCION 1 */}
|
|
43
44
|
<DropdownMultiSelect
|
|
44
45
|
{...args}
|
|
45
46
|
values={filters}
|
|
@@ -49,32 +50,21 @@ const Template = (args) => {
|
|
|
49
50
|
onToggle={handleToggle}
|
|
50
51
|
object={true}
|
|
51
52
|
nameKey='name'
|
|
53
|
+
nameKey1='name1'
|
|
52
54
|
idKey={'id'}
|
|
53
55
|
inputLabel={'Filters (array de objetos)'}
|
|
54
56
|
focus={show}
|
|
55
|
-
hasId={
|
|
57
|
+
hasId={false}
|
|
56
58
|
errorRequired={errorRequired}
|
|
57
59
|
setErrorRequiered={setErrorRequired}
|
|
58
60
|
validate={true}
|
|
61
|
+
disableHash={true}
|
|
62
|
+
overflow={true}
|
|
59
63
|
/>
|
|
60
|
-
<button className='my-3' onClick={() => setErrorRequired(true)}>Validate</button>
|
|
61
|
-
|
|
62
64
|
|
|
63
|
-
{
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
values={stringFilters}
|
|
67
|
-
valuesSelected={selectedStringValues}
|
|
68
|
-
setValuesSelected={setSelectedStringValues}
|
|
69
|
-
show={show}
|
|
70
|
-
onToggle={handleToggle}
|
|
71
|
-
object={false}
|
|
72
|
-
nameKey='name'
|
|
73
|
-
idKey={'id'}
|
|
74
|
-
inputLabel={'Filters (array de strings)'}
|
|
75
|
-
focus={show}
|
|
76
|
-
hasId={true}
|
|
77
|
-
/>
|
|
65
|
+
<button className='my-3' onClick={() => setErrorRequired(true)}>
|
|
66
|
+
Validate
|
|
67
|
+
</button>
|
|
78
68
|
</>
|
|
79
69
|
);
|
|
80
70
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { Children } from 'react';
|
|
1
|
+
import React, { Children, useState } from 'react';
|
|
2
2
|
import { Sidebar } from '../components/Navigation';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
@@ -12,12 +12,29 @@ const Template = (args) => {
|
|
|
12
12
|
{
|
|
13
13
|
title: 'Main menu', // section.title
|
|
14
14
|
links: [
|
|
15
|
-
|
|
16
15
|
{
|
|
17
|
-
name: '
|
|
18
|
-
icon: 'home',
|
|
16
|
+
name: 'Campaings',
|
|
17
|
+
icon: 'home',
|
|
19
18
|
url: '/home',
|
|
20
19
|
children: [],
|
|
20
|
+
pendingLength: 5, // explanation(number) Pass the length of the array from the relevant endpoint data, for example, if there are pending campaigns.
|
|
21
|
+
// Not required, only if you want to display a type of pendingType ('warning' or 'badge').
|
|
22
|
+
pendingType: 'warning',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'Reports',
|
|
26
|
+
icon: 'home',
|
|
27
|
+
url: '/home',
|
|
28
|
+
children: [
|
|
29
|
+
/* {
|
|
30
|
+
name: 'Item 1',
|
|
31
|
+
icon: 'home',
|
|
32
|
+
url: '/home',
|
|
33
|
+
children: [],
|
|
34
|
+
}, */
|
|
35
|
+
],
|
|
36
|
+
pendingLength: 5,
|
|
37
|
+
pendingType: 'badge',
|
|
21
38
|
},
|
|
22
39
|
],
|
|
23
40
|
},
|
|
@@ -26,7 +43,7 @@ const Template = (args) => {
|
|
|
26
43
|
links: [
|
|
27
44
|
{
|
|
28
45
|
name: 'Impressions',
|
|
29
|
-
icon: 'table',
|
|
46
|
+
icon: 'table',
|
|
30
47
|
url: '',
|
|
31
48
|
children: [
|
|
32
49
|
{
|
|
@@ -44,6 +61,14 @@ const Template = (args) => {
|
|
|
44
61
|
name: 'Monthly impressions by...',
|
|
45
62
|
url: '/impressions',
|
|
46
63
|
},
|
|
64
|
+
{
|
|
65
|
+
name: '2Monthly impressions by...',
|
|
66
|
+
url: '/2impressions',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: '3Monthly impressions by...',
|
|
70
|
+
url: '/3impressions',
|
|
71
|
+
},
|
|
47
72
|
],
|
|
48
73
|
},
|
|
49
74
|
],
|
|
@@ -117,7 +142,7 @@ const Template = (args) => {
|
|
|
117
142
|
php_session_id: 'u7o2br84i92jmfkdrqen10ngp1',
|
|
118
143
|
is_api2_login: true,
|
|
119
144
|
};
|
|
120
|
-
|
|
145
|
+
|
|
121
146
|
return (
|
|
122
147
|
<div className='container-fluid'>
|
|
123
148
|
<Sidebar
|