@visns-studio/visns-components 5.6.0 → 5.6.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/package.json
CHANGED
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
85
85
|
},
|
|
86
86
|
"name": "@visns-studio/visns-components",
|
|
87
|
-
"version": "5.6.
|
|
87
|
+
"version": "5.6.2",
|
|
88
88
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
89
89
|
"main": "src/index.js",
|
|
90
90
|
"files": [
|
|
@@ -5,6 +5,18 @@ import Select, { createFilter } from 'react-select';
|
|
|
5
5
|
import CreatableSelect from 'react-select/creatable';
|
|
6
6
|
import styles from './styles/MultiSelect.module.scss';
|
|
7
7
|
|
|
8
|
+
// Helper function to detect if the device is a mobile/touch device
|
|
9
|
+
const isTouchDevice = () => {
|
|
10
|
+
// Check if window is defined (to avoid SSR issues)
|
|
11
|
+
if (typeof window === 'undefined') return false;
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
'ontouchstart' in window ||
|
|
15
|
+
(navigator && navigator.maxTouchPoints > 0) ||
|
|
16
|
+
(navigator && navigator.msMaxTouchPoints > 0)
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
8
20
|
function MultiSelect({
|
|
9
21
|
className,
|
|
10
22
|
inputValue = [], // Default to an empty array
|
|
@@ -20,6 +32,15 @@ function MultiSelect({
|
|
|
20
32
|
const [selectOptions, setSelectOptions] = useState([]);
|
|
21
33
|
const [selectValue, setSelectValue] = useState([]);
|
|
22
34
|
const prevInputValueRef = useRef();
|
|
35
|
+
const [menuPlacement, setMenuPlacement] = useState('bottom');
|
|
36
|
+
|
|
37
|
+
// Detect if it's a touch device and set menu placement accordingly
|
|
38
|
+
// This helps prevent the dropdown from being hidden by the onscreen keyboard on mobile devices
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (isTouchDevice()) {
|
|
41
|
+
setMenuPlacement('top'); // Open dropdown above the input on touch devices
|
|
42
|
+
}
|
|
43
|
+
}, []);
|
|
23
44
|
|
|
24
45
|
useEffect(() => {
|
|
25
46
|
const _options =
|
|
@@ -99,6 +120,24 @@ function MultiSelect({
|
|
|
99
120
|
|
|
100
121
|
const SelectComponent = isCreatable ? CreatableSelect : Select;
|
|
101
122
|
|
|
123
|
+
// Handle menu opening to ensure it's visible on mobile
|
|
124
|
+
const handleMenuOpen = () => {
|
|
125
|
+
if (isTouchDevice()) {
|
|
126
|
+
// Give a small delay for the menu to render
|
|
127
|
+
setTimeout(() => {
|
|
128
|
+
const menuElement = document.querySelector(
|
|
129
|
+
'.visns-select__menu'
|
|
130
|
+
);
|
|
131
|
+
if (menuElement) {
|
|
132
|
+
menuElement.scrollIntoView({
|
|
133
|
+
behavior: 'smooth',
|
|
134
|
+
block: 'nearest',
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}, 50);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
102
141
|
return (
|
|
103
142
|
<SelectComponent
|
|
104
143
|
closeMenuOnSelect={!multi || settings.limit === 1}
|
|
@@ -109,6 +148,8 @@ function MultiSelect({
|
|
|
109
148
|
components={{ SelectList }}
|
|
110
149
|
options={selectOptions}
|
|
111
150
|
menuPortalTarget={document.body}
|
|
151
|
+
menuPlacement={menuPlacement}
|
|
152
|
+
onMenuOpen={handleMenuOpen}
|
|
112
153
|
onChange={(inputValue, action) => {
|
|
113
154
|
// Special handling for limit=1: keep only the most recent selection
|
|
114
155
|
if (
|
|
@@ -135,6 +176,10 @@ function MultiSelect({
|
|
|
135
176
|
...provided,
|
|
136
177
|
zIndex: 99999,
|
|
137
178
|
}),
|
|
179
|
+
option: (base) => ({
|
|
180
|
+
...base,
|
|
181
|
+
padding: isTouchDevice() ? '12px 15px' : base.padding, // Larger padding for touch devices
|
|
182
|
+
}),
|
|
138
183
|
menuPortal: (base) => ({
|
|
139
184
|
...base,
|
|
140
185
|
zIndex: 99999,
|
|
@@ -144,7 +189,9 @@ function MultiSelect({
|
|
|
144
189
|
minHeight:
|
|
145
190
|
style && style.multi_select_height
|
|
146
191
|
? style.multi_select_height
|
|
147
|
-
:
|
|
192
|
+
: isTouchDevice()
|
|
193
|
+
? '44px'
|
|
194
|
+
: '50px', // Apple's recommended minimum touch target size
|
|
148
195
|
height: 'auto', // Allow height to grow with content
|
|
149
196
|
}),
|
|
150
197
|
valueContainer: (base) => ({
|
|
@@ -9,6 +9,7 @@ function TableFilter({
|
|
|
9
9
|
type,
|
|
10
10
|
}) {
|
|
11
11
|
const [visibleChildren, setVisibleChildren] = useState(null);
|
|
12
|
+
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
|
12
13
|
const isFirstRender = useRef(true);
|
|
13
14
|
|
|
14
15
|
useEffect(() => {
|
|
@@ -116,6 +117,9 @@ function TableFilter({
|
|
|
116
117
|
if (collapsible && filtertype === 'parent') {
|
|
117
118
|
setVisibleChildren(id);
|
|
118
119
|
}
|
|
120
|
+
|
|
121
|
+
// Close mobile menu after selection on small screens
|
|
122
|
+
setMobileMenuOpen(false);
|
|
119
123
|
};
|
|
120
124
|
|
|
121
125
|
const renderContent = (d) => {
|
|
@@ -184,14 +188,40 @@ function TableFilter({
|
|
|
184
188
|
}
|
|
185
189
|
};
|
|
186
190
|
|
|
191
|
+
const toggleMobileMenu = () => {
|
|
192
|
+
setMobileMenuOpen(!mobileMenuOpen);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// Find active filter for mobile display
|
|
196
|
+
const activeFilter = filters.find((filter) => filter.show === true);
|
|
197
|
+
const activeLabel = activeFilter ? activeFilter.label : 'Select Option';
|
|
198
|
+
|
|
187
199
|
return (
|
|
188
|
-
<
|
|
189
|
-
{
|
|
190
|
-
<
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
200
|
+
<div className={styles.tableFilterContainer}>
|
|
201
|
+
<div className={styles.mobileToggle} onClick={toggleMobileMenu}>
|
|
202
|
+
<span className={styles.activeFilterLabel}>{activeLabel}</span>
|
|
203
|
+
<span
|
|
204
|
+
className={`${styles.mobileMenuIcon} ${
|
|
205
|
+
mobileMenuOpen ? styles.open : ''
|
|
206
|
+
}`}
|
|
207
|
+
>
|
|
208
|
+
<span></span>
|
|
209
|
+
<span></span>
|
|
210
|
+
<span></span>
|
|
211
|
+
</span>
|
|
212
|
+
</div>
|
|
213
|
+
<ul
|
|
214
|
+
className={`${styles.tableFilter} ${
|
|
215
|
+
mobileMenuOpen ? styles.mobileOpen : ''
|
|
216
|
+
}`}
|
|
217
|
+
>
|
|
218
|
+
{filters.map((item, key) => (
|
|
219
|
+
<React.Fragment key={'table-filter-' + key}>
|
|
220
|
+
{renderContent(item)}
|
|
221
|
+
</React.Fragment>
|
|
222
|
+
))}
|
|
223
|
+
</ul>
|
|
224
|
+
</div>
|
|
195
225
|
);
|
|
196
226
|
}
|
|
197
227
|
|
|
@@ -40,6 +40,17 @@
|
|
|
40
40
|
|
|
41
41
|
.navwrap {
|
|
42
42
|
flex: 1;
|
|
43
|
+
overflow-x: auto;
|
|
44
|
+
-webkit-overflow-scrolling: touch; /* For smooth scrolling on iOS */
|
|
45
|
+
|
|
46
|
+
/* Hide scrollbar for most browsers but keep functionality */
|
|
47
|
+
scrollbar-width: none; /* Firefox */
|
|
48
|
+
-ms-overflow-style: none; /* IE and Edge */
|
|
49
|
+
|
|
50
|
+
/* Hide scrollbar for Chrome/Safari/Opera */
|
|
51
|
+
&::-webkit-scrollbar {
|
|
52
|
+
display: none;
|
|
53
|
+
}
|
|
43
54
|
}
|
|
44
55
|
|
|
45
56
|
.app-nav {
|
|
@@ -51,6 +62,8 @@
|
|
|
51
62
|
list-style: none;
|
|
52
63
|
align-items: center;
|
|
53
64
|
padding: 0;
|
|
65
|
+
width: max-content; /* Ensure it takes the width of all items */
|
|
66
|
+
min-width: 100%; /* Start at 100% width */
|
|
54
67
|
|
|
55
68
|
.navDropdown {
|
|
56
69
|
border-radius: var(--br);
|
|
@@ -64,6 +77,7 @@
|
|
|
64
77
|
transition: all 0.15s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
65
78
|
box-sizing: border-box;
|
|
66
79
|
position: relative;
|
|
80
|
+
flex-shrink: 0; /* Prevent items from shrinking too much */
|
|
67
81
|
|
|
68
82
|
a,
|
|
69
83
|
span {
|
|
@@ -441,6 +455,15 @@
|
|
|
441
455
|
.navwrap {
|
|
442
456
|
width: 100%;
|
|
443
457
|
position: relative;
|
|
458
|
+
overflow-y: auto; /* Enable vertical scrolling */
|
|
459
|
+
max-height: calc(100vh - 50px); /* Subtract the logo height */
|
|
460
|
+
scrollbar-width: none; /* Firefox */
|
|
461
|
+
-ms-overflow-style: none; /* IE and Edge */
|
|
462
|
+
|
|
463
|
+
/* Hide scrollbar for Chrome/Safari/Opera */
|
|
464
|
+
&::-webkit-scrollbar {
|
|
465
|
+
display: none;
|
|
466
|
+
}
|
|
444
467
|
|
|
445
468
|
.app-nav {
|
|
446
469
|
width: 100%;
|
|
@@ -591,6 +614,15 @@
|
|
|
591
614
|
flex-wrap: nowrap;
|
|
592
615
|
justify-content: space-between;
|
|
593
616
|
align-items: center;
|
|
617
|
+
overflow-x: auto; /* Allow horizontal scrolling if needed */
|
|
618
|
+
-webkit-overflow-scrolling: touch;
|
|
619
|
+
scrollbar-width: none; /* Firefox */
|
|
620
|
+
-ms-overflow-style: none; /* IE and Edge */
|
|
621
|
+
|
|
622
|
+
/* Hide scrollbar for Chrome/Safari/Opera */
|
|
623
|
+
&::-webkit-scrollbar {
|
|
624
|
+
display: none;
|
|
625
|
+
}
|
|
594
626
|
}
|
|
595
627
|
|
|
596
628
|
.content-title {
|
|
@@ -644,6 +676,17 @@
|
|
|
644
676
|
}
|
|
645
677
|
|
|
646
678
|
@media (max-width: 1024px) {
|
|
679
|
+
.hwrap {
|
|
680
|
+
grid-template-columns: auto 1fr auto;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.navwrap {
|
|
684
|
+
position: relative;
|
|
685
|
+
overflow-x: auto;
|
|
686
|
+
-webkit-overflow-scrolling: touch;
|
|
687
|
+
padding: 0;
|
|
688
|
+
/* No fade indicators - they don't work well with scrolling */
|
|
689
|
+
}
|
|
647
690
|
.app-container {
|
|
648
691
|
width: 100%;
|
|
649
692
|
min-height: 100vh;
|
|
@@ -914,6 +957,19 @@
|
|
|
914
957
|
}
|
|
915
958
|
|
|
916
959
|
@media (max-width: 960px) {
|
|
960
|
+
.hwrap {
|
|
961
|
+
grid-template-columns: auto 1fr auto;
|
|
962
|
+
gap: 0.5rem;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
.navwrap {
|
|
966
|
+
margin: 0;
|
|
967
|
+
padding: 0;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
.app-nav {
|
|
971
|
+
gap: 0.25rem; /* Reduce gap between items on smaller screens */
|
|
972
|
+
}
|
|
917
973
|
.userdetails {
|
|
918
974
|
display: none;
|
|
919
975
|
visibility: hidden;
|
|
@@ -953,6 +1009,13 @@
|
|
|
953
1009
|
flex-wrap: nowrap;
|
|
954
1010
|
align-content: center;
|
|
955
1011
|
width: 50%;
|
|
1012
|
+
min-width: 150px; /* Ensure minimum width on small screens */
|
|
1013
|
+
position: relative;
|
|
1014
|
+
|
|
1015
|
+
input {
|
|
1016
|
+
min-width: 0; /* Allow input to shrink below its content size */
|
|
1017
|
+
flex: 1; /* Take available space */
|
|
1018
|
+
}
|
|
956
1019
|
|
|
957
1020
|
button {
|
|
958
1021
|
width: max-content;
|
|
@@ -962,6 +1025,7 @@
|
|
|
962
1025
|
background: var(--primary-color);
|
|
963
1026
|
appearance: none;
|
|
964
1027
|
border-radius: var(--br);
|
|
1028
|
+
flex-shrink: 0; /* Prevent button from shrinking */
|
|
965
1029
|
|
|
966
1030
|
svg {
|
|
967
1031
|
display: block;
|
|
@@ -970,4 +1034,14 @@
|
|
|
970
1034
|
max-width: 20px;
|
|
971
1035
|
}
|
|
972
1036
|
}
|
|
1037
|
+
|
|
1038
|
+
@media (max-width: 768px) {
|
|
1039
|
+
width: auto; /* Allow to take natural width */
|
|
1040
|
+
flex: 1; /* Take available space */
|
|
1041
|
+
|
|
1042
|
+
button {
|
|
1043
|
+
margin: 0 0.25rem;
|
|
1044
|
+
padding: 0.15rem 0.35rem;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
973
1047
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
.tableFilterContainer {
|
|
2
|
+
width: 100%;
|
|
3
|
+
position: relative;
|
|
4
|
+
display: block;
|
|
5
|
+
}
|
|
6
|
+
|
|
1
7
|
.tableFilter {
|
|
2
8
|
list-style: none;
|
|
3
9
|
padding: 0;
|
|
4
10
|
margin: 0;
|
|
5
11
|
font-size: 1rem;
|
|
12
|
+
width: 100%;
|
|
6
13
|
}
|
|
7
14
|
|
|
8
15
|
.collapsibleMenu {
|
|
@@ -51,3 +58,81 @@
|
|
|
51
58
|
background: var(--item-color) !important;
|
|
52
59
|
color: var(--paragraph-color) !important;
|
|
53
60
|
}
|
|
61
|
+
|
|
62
|
+
/* Mobile menu toggle button */
|
|
63
|
+
.mobileToggle {
|
|
64
|
+
display: none;
|
|
65
|
+
align-items: center;
|
|
66
|
+
justify-content: space-between;
|
|
67
|
+
padding: 12px 15px;
|
|
68
|
+
background: var(--primary-color, #0b3b2e);
|
|
69
|
+
color: white;
|
|
70
|
+
border-radius: 4px;
|
|
71
|
+
cursor: pointer;
|
|
72
|
+
margin-bottom: 10px;
|
|
73
|
+
border: none;
|
|
74
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.activeFilterLabel {
|
|
78
|
+
font-weight: 600;
|
|
79
|
+
color: white;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.mobileMenuIcon {
|
|
83
|
+
display: flex;
|
|
84
|
+
flex-direction: column;
|
|
85
|
+
justify-content: space-between;
|
|
86
|
+
width: 20px;
|
|
87
|
+
height: 14px;
|
|
88
|
+
position: relative;
|
|
89
|
+
transition: all 0.3s ease;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.mobileMenuIcon span {
|
|
93
|
+
display: block;
|
|
94
|
+
height: 2px;
|
|
95
|
+
width: 100%;
|
|
96
|
+
background-color: white;
|
|
97
|
+
border-radius: 2px;
|
|
98
|
+
transition: all 0.3s ease;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.mobileMenuIcon.open span:nth-child(1) {
|
|
102
|
+
transform: translateY(6px) rotate(45deg);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.mobileMenuIcon.open span:nth-child(2) {
|
|
106
|
+
opacity: 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.mobileMenuIcon.open span:nth-child(3) {
|
|
110
|
+
transform: translateY(-6px) rotate(-45deg);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* Media queries for responsive design */
|
|
114
|
+
@media (max-width: 1024px) {
|
|
115
|
+
.mobileToggle {
|
|
116
|
+
display: flex;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.tableFilter {
|
|
120
|
+
display: none;
|
|
121
|
+
max-height: 0;
|
|
122
|
+
overflow: hidden;
|
|
123
|
+
transition: max-height 0.3s ease;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.tableFilter.mobileOpen {
|
|
127
|
+
display: block;
|
|
128
|
+
max-height: 1000px;
|
|
129
|
+
overflow-y: auto;
|
|
130
|
+
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
131
|
+
border-radius: 4px;
|
|
132
|
+
margin-bottom: 10px;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.link {
|
|
136
|
+
padding: 12px 20px; /* Larger touch targets for mobile */
|
|
137
|
+
}
|
|
138
|
+
}
|