@visns-studio/visns-components 5.8.19 → 5.9.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.
@@ -1112,8 +1112,8 @@ function Field({
1112
1112
  ? settings.options
1113
1113
  : options
1114
1114
  }
1115
- isSearchable={settings.isSearchable || true}
1116
- isCreatable={settings.isCreatable || false}
1115
+ isSearchable={settings.isSearchable ?? true}
1116
+ isCreatable={settings.isCreatable ?? false}
1117
1117
  dataOptions={dataOptions}
1118
1118
  style={style}
1119
1119
  />
@@ -25,7 +25,9 @@ const CustomOption = (props) => {
25
25
  <div className={styles.option}>
26
26
  <div className={styles.optionLabel}>{children}</div>
27
27
  {data.description && (
28
- <div className={styles.optionDescription}>{data.description}</div>
28
+ <div className={styles.optionDescription}>
29
+ {data.description}
30
+ </div>
29
31
  )}
30
32
  </div>
31
33
  </components.Option>
@@ -40,7 +42,9 @@ const CustomMultiValue = (props) => {
40
42
  <div className={styles.multiValue}>
41
43
  <div className={styles.multiValueLabel}>{children}</div>
42
44
  {data.description && (
43
- <div className={styles.multiValueDescription}>{data.description}</div>
45
+ <div className={styles.multiValueDescription}>
46
+ {data.description}
47
+ </div>
44
48
  )}
45
49
  </div>
46
50
  </components.MultiValue>
@@ -111,14 +115,14 @@ function MultiSelect({
111
115
  if (item.description) return item;
112
116
 
113
117
  // Try to find a matching option with description
114
- const matchingOption = selectOptions.find(opt =>
115
- opt.id === item.id || opt.value === item.id
118
+ const matchingOption = selectOptions.find(
119
+ (opt) => opt.id === item.id || opt.value === item.id
116
120
  );
117
121
 
118
122
  if (matchingOption && matchingOption.description) {
119
123
  return {
120
124
  ...item,
121
- description: matchingOption.description
125
+ description: matchingOption.description,
122
126
  };
123
127
  }
124
128
 
@@ -130,7 +134,11 @@ function MultiSelect({
130
134
  const enrichedItem = findMatchingOption(a);
131
135
  return {
132
136
  value: enrichedItem.id,
133
- label: enrichedItem.label || enrichedItem.name || enrichedItem.description || 'Unknown',
137
+ label:
138
+ enrichedItem.label ||
139
+ enrichedItem.name ||
140
+ enrichedItem.description ||
141
+ 'Unknown',
134
142
  // Make sure description is preserved
135
143
  description: enrichedItem.description || null,
136
144
  ...enrichedItem,
@@ -210,7 +218,7 @@ function MultiSelect({
210
218
  components={{
211
219
  SelectList,
212
220
  Option: CustomOption,
213
- MultiValue: CustomMultiValue
221
+ MultiValue: CustomMultiValue,
214
222
  }}
215
223
  options={selectOptions}
216
224
  menuPortalTarget={document.body}
@@ -301,21 +309,33 @@ function MultiSelect({
301
309
  padding: '2px 4px',
302
310
  minHeight: '30px',
303
311
  display: 'flex',
304
- flexDirection: 'column',
305
- alignItems: 'flex-start',
312
+ flexDirection: 'row',
313
+ alignItems: 'center',
314
+ backgroundColor: '#e2e8f0',
315
+ borderRadius: '4px',
306
316
  }),
307
317
  multiValueLabel: (base) => ({
308
318
  ...base,
309
- padding: '0',
319
+ padding: '0 4px 0 0',
310
320
  display: 'flex',
311
321
  flexDirection: 'column',
312
- width: '100%',
322
+ flex: '1',
323
+ minWidth: '0',
313
324
  }),
314
325
  multiValueRemove: (base) => ({
315
326
  ...base,
316
327
  padding: '0 4px',
317
- alignSelf: 'flex-start',
318
- marginTop: '2px',
328
+ display: 'flex',
329
+ alignItems: 'center',
330
+ justifyContent: 'center',
331
+ margin: '0',
332
+ borderRadius: '0 4px 4px 0',
333
+ backgroundColor: 'transparent',
334
+ transition: 'background-color 0.2s ease',
335
+ '&:hover': {
336
+ backgroundColor: '#dc2626',
337
+ color: 'white',
338
+ },
319
339
  }),
320
340
  }}
321
341
  value={selectValue}
@@ -17,6 +17,20 @@ import '../../styles/global.css';
17
17
  * // other form properties
18
18
  * }
19
19
  * }
20
+ *
21
+ * Modal Vertical Alignment:
22
+ * To position the modal toward the top of the viewport instead of center, add the `verticalAlign: "top"` property to the form object.
23
+ * Example:
24
+ * {
25
+ * id: 'overview',
26
+ * type: 'overview',
27
+ * form: {
28
+ * verticalAlign: "top",
29
+ * primaryKey: "id",
30
+ * url: "/ajax/jobs",
31
+ * // other form properties
32
+ * }
33
+ * }
20
34
  */
21
35
 
22
36
  import React, { useEffect, useRef, useState } from 'react';
@@ -2753,9 +2767,25 @@ function GenericDetail({
2753
2767
  open={modalShow}
2754
2768
  onClose={modalClose}
2755
2769
  closeOnDocumentClick={false}
2756
- contentStyle={{ width: '80vw', maxWidth: '1200px' }}
2770
+ contentStyle={{
2771
+ width: '80vw',
2772
+ maxWidth: '1200px',
2773
+ ...(formData.verticalAlign === 'top' && {
2774
+ position: 'fixed',
2775
+ top: '5vh',
2776
+ left: '50%',
2777
+ transform: 'translateX(-50%)',
2778
+ margin: '0',
2779
+ }),
2780
+ }}
2757
2781
  >
2758
- <div className="modalwrap top--modal modalWide">
2782
+ <div
2783
+ className={`modalwrap top--modal modalWide ${
2784
+ formData.verticalAlign === 'top'
2785
+ ? 'modal-top-aligned'
2786
+ : ''
2787
+ }`}
2788
+ >
2759
2789
  <div className="modal">
2760
2790
  <Form
2761
2791
  closeModal={modalClose}
@@ -21,19 +21,20 @@
21
21
  }
22
22
  }
23
23
 
24
- /* Clock button styles */
24
+ /* Clock button styles - Compact version */
25
25
  .clockButton {
26
26
  display: flex;
27
27
  align-items: center;
28
28
  justify-content: center;
29
- width: 40px;
30
- height: 40px;
31
- border-radius: 4px;
29
+ width: 28px;
30
+ height: 28px;
31
+ border-radius: 3px;
32
32
  background-color: #2b6cb0; /* Matching blue from screenshot */
33
33
  border: none;
34
34
  cursor: pointer;
35
35
  transition: all 0.2s ease;
36
36
  margin: 0 auto;
37
+ padding: 0;
37
38
 
38
39
  &:hover {
39
40
  background-color: #2563a0; /* Slightly darker blue on hover */
@@ -109,13 +110,22 @@
109
110
  justify-content: flex-start;
110
111
  align-items: center;
111
112
  gap: 0.1rem;
113
+ padding: 3px 0;
112
114
 
113
115
  span {
114
116
  display: flex;
115
117
  align-items: center;
116
118
  position: relative;
117
- width: 18px;
118
- height: 18px;
119
+ width: 20px;
120
+ height: 20px;
121
+ padding: 3px;
122
+ cursor: pointer;
123
+ border-radius: 3px;
124
+ transition: background-color 0.2s ease;
125
+
126
+ &:hover {
127
+ background-color: rgba(var(--primary-rgb, 59, 130, 246), 0.1);
128
+ }
119
129
 
120
130
  svg {
121
131
  width: 18px;
@@ -594,6 +604,19 @@
594
604
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
595
605
  }
596
606
 
607
+ /* Relocated auto-refresh controls (when placed at bottom) */
608
+ .autoRefreshContainerRelocated {
609
+ display: inline-flex;
610
+ align-items: center;
611
+ padding: 0 15px;
612
+ height: 38px;
613
+ background-color: #f9fafb;
614
+ border: 1px solid #d1d5db;
615
+ border-radius: var(--br, 4px);
616
+ margin: 0;
617
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
618
+ }
619
+
597
620
  .autoRefreshLabel {
598
621
  display: flex;
599
622
  align-items: center;
@@ -720,6 +743,15 @@
720
743
  }
721
744
  }
722
745
 
746
+ /* Bottom container for relocated controls */
747
+ .dataGridBottomContainer {
748
+ display: flex;
749
+ justify-content: flex-end;
750
+ align-items: center;
751
+ margin-top: 8px;
752
+ padding: 0 5px;
753
+ }
754
+
723
755
  /* Original filter input styles kept for backward compatibility */
724
756
  .filterInput {
725
757
  display: flex;
@@ -32,8 +32,12 @@
32
32
 
33
33
  .multiValue {
34
34
  display: flex;
35
- flex-direction: column;
36
- gap: 1px;
35
+ flex-direction: row;
36
+ align-items: center;
37
+ gap: 4px;
38
+ background-color: #e2e8f0;
39
+ border-radius: 4px;
40
+ padding: 2px 4px;
37
41
  }
38
42
 
39
43
  .multiValueLabel {
@@ -46,7 +50,12 @@
46
50
  color: rgba(0, 0, 0, 0.7); /* Darker color for better contrast */
47
51
  font-weight: 400;
48
52
  line-height: 1.1;
49
- background-color: rgba(255, 255, 255, 0.7); /* Semi-transparent white background */
53
+ background-color: rgba(
54
+ 255,
55
+ 255,
56
+ 255,
57
+ 0.7
58
+ ); /* Semi-transparent white background */
50
59
  padding: 1px 3px;
51
60
  border-radius: 2px;
52
61
  margin-top: 1px;
@@ -109,21 +118,34 @@
109
118
  padding: 2px 4px !important;
110
119
  min-height: 30px !important;
111
120
  display: flex !important;
112
- flex-direction: column !important;
113
- align-items: flex-start !important;
121
+ flex-direction: row !important;
122
+ align-items: center !important;
123
+ background-color: #e2e8f0 !important;
124
+ border-radius: 4px !important;
114
125
  }
115
126
 
116
127
  .visns-select__multi-value__label {
117
- padding: 0 !important;
128
+ padding: 0 4px 0 0 !important;
118
129
  display: flex !important;
119
130
  flex-direction: column !important;
120
- width: 100% !important;
131
+ flex: 1 !important;
132
+ min-width: 0 !important;
121
133
  }
122
134
 
123
135
  .visns-select__multi-value__remove {
124
136
  padding: 0 4px !important;
125
- align-self: flex-start !important;
126
- margin-top: 2px !important;
137
+ display: flex !important;
138
+ align-items: center !important;
139
+ justify-content: center !important;
140
+ margin: 0 !important;
141
+ border-radius: 0 4px 4px 0 !important;
142
+ background-color: transparent !important;
143
+ transition: background-color 0.2s ease !important;
144
+ }
145
+
146
+ .visns-select__multi-value__remove:hover {
147
+ background-color: #dc2626 !important;
148
+ color: white !important;
127
149
  }
128
150
 
129
151
  /* Fix for modals */
@@ -193,7 +193,38 @@
193
193
  }
194
194
 
195
195
  /* Media queries for responsive design */
196
- @media (max-width: 1024px) {
196
+
197
+ /* Tablet view (961px to 1024px) - Keep filter expanded in left container */
198
+ @media (max-width: 1024px) and (min-width: 961px) {
199
+ /* Ensure filter remains visible and properly styled for tablets */
200
+ .tableFilter {
201
+ display: block;
202
+ /* Maintain normal styling for tablet view */
203
+ }
204
+
205
+ .mobileToggle {
206
+ display: none; /* Hide hamburger menu on tablets */
207
+ }
208
+
209
+ /* Slightly adjust padding for better tablet experience */
210
+ .parentLink {
211
+ padding: 9px 16px;
212
+ font-size: 0.9rem;
213
+ }
214
+
215
+ .link {
216
+ padding: 9px 16px;
217
+ font-size: 0.85rem;
218
+ }
219
+
220
+ .childLink {
221
+ padding: 7px 16px 7px 26px;
222
+ font-size: 0.85rem;
223
+ }
224
+ }
225
+
226
+ /* Phone view (960px and below) - Use hamburger menu when navigation moves to top */
227
+ @media (max-width: 960px) {
197
228
  .mobileToggle {
198
229
  display: flex;
199
230
  }
@@ -21,9 +21,15 @@
21
21
  border-radius: 0 !important;
22
22
  }
23
23
 
24
- /* Ensure consistent border radius for cells */
24
+ /* Ensure consistent border radius for cells and reduce padding for compact rows */
25
25
  .InovuaReactDataGrid__cell {
26
26
  border-radius: 0 !important;
27
+ padding: 6px 8px !important; /* Reduced from default padding */
28
+ }
29
+
30
+ /* Reduce header cell padding as well */
31
+ .InovuaReactDataGrid__header-cell {
32
+ padding: 6px 8px !important;
27
33
  }
28
34
 
29
35
  /* Fix for focus outline */
@@ -32,3 +38,171 @@
32
38
  outline: none !important;
33
39
  box-shadow: 0 0 0 2px rgba(var(--primary-rgb, 59, 130, 246), 0.2) !important;
34
40
  }
41
+
42
+ /* Checkbox column improvements for touch devices - Compact version */
43
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column'] {
44
+ padding: 6px 8px !important; /* Reduced padding for compact rows */
45
+ min-width: 60px !important;
46
+ width: 60px !important;
47
+ max-width: 60px !important;
48
+ position: relative !important;
49
+ cursor: pointer !important;
50
+ display: flex !important;
51
+ align-items: center !important;
52
+ justify-content: center !important;
53
+ /* Ensure the entire cell is clickable */
54
+ user-select: none !important;
55
+ -webkit-user-select: none !important;
56
+ -moz-user-select: none !important;
57
+ -ms-user-select: none !important;
58
+ }
59
+
60
+ /* Improve checkbox touch targets */
61
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
62
+ input[type='checkbox'] {
63
+ width: 20px !important;
64
+ height: 20px !important;
65
+ margin: 0 !important;
66
+ cursor: pointer !important;
67
+ position: relative !important;
68
+ z-index: 2 !important;
69
+ }
70
+
71
+ /* Create larger touch target area around checkbox */
72
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
73
+ .InovuaReactDataGrid__checkbox-wrapper,
74
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
75
+ .InovuaReactDataGrid__checkbox {
76
+ display: flex !important;
77
+ align-items: center !important;
78
+ justify-content: center !important;
79
+ min-height: 44px !important;
80
+ min-width: 44px !important;
81
+ padding: 12px !important;
82
+ margin: -12px !important;
83
+ cursor: pointer !important;
84
+ border-radius: 4px !important;
85
+ transition: background-color 0.2s ease !important;
86
+ }
87
+
88
+ /* Touch-friendly hover effect for the entire cell */
89
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']:hover {
90
+ background-color: rgba(var(--primary-rgb, 59, 130, 246), 0.05) !important;
91
+ }
92
+
93
+ /* Touch-friendly hover effect for checkbox wrapper */
94
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
95
+ .InovuaReactDataGrid__checkbox-wrapper:hover,
96
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
97
+ .InovuaReactDataGrid__checkbox:hover {
98
+ background-color: rgba(var(--primary-rgb, 59, 130, 246), 0.1) !important;
99
+ }
100
+
101
+ /* Header checkbox improvements - Compact version */
102
+ .InovuaReactDataGrid__header-cell[data-column-id='__checkbox-column'] {
103
+ padding: 6px 8px !important; /* Reduced padding for compact rows */
104
+ min-width: 60px !important;
105
+ width: 60px !important;
106
+ max-width: 60px !important;
107
+ }
108
+
109
+ .InovuaReactDataGrid__header-cell[data-column-id='__checkbox-column']
110
+ input[type='checkbox'] {
111
+ width: 20px !important;
112
+ height: 20px !important;
113
+ margin: 0 !important;
114
+ cursor: pointer !important;
115
+ }
116
+
117
+ /* Prevent text selection in checkbox column */
118
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column'] {
119
+ user-select: none !important;
120
+ -webkit-user-select: none !important;
121
+ -moz-user-select: none !important;
122
+ -ms-user-select: none !important;
123
+ }
124
+
125
+ /* Additional checkbox styling for better UX */
126
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
127
+ .InovuaReactDataGrid__cell-content {
128
+ display: flex !important;
129
+ align-items: center !important;
130
+ justify-content: center !important;
131
+ width: 100% !important;
132
+ height: 100% !important;
133
+ }
134
+
135
+ /* Focus styles for accessibility */
136
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
137
+ input[type='checkbox']:focus {
138
+ outline: 2px solid rgba(var(--primary-rgb, 59, 130, 246), 0.5) !important;
139
+ outline-offset: 2px !important;
140
+ }
141
+
142
+ /* Ensure checkbox column doesn't interfere with row hover */
143
+ .InovuaReactDataGrid__row:hover
144
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column'] {
145
+ background-color: inherit !important;
146
+ }
147
+
148
+ /* Mobile-specific improvements - Compact version */
149
+ @media (max-width: 768px) {
150
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column'] {
151
+ min-width: 70px !important;
152
+ width: 70px !important;
153
+ max-width: 70px !important;
154
+ padding: 8px 12px !important; /* Reduced padding for compact rows */
155
+ }
156
+
157
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
158
+ input[type='checkbox'] {
159
+ width: 24px !important;
160
+ height: 24px !important;
161
+ }
162
+
163
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
164
+ .InovuaReactDataGrid__checkbox-wrapper,
165
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
166
+ .InovuaReactDataGrid__checkbox {
167
+ min-height: 48px !important;
168
+ min-width: 48px !important;
169
+ padding: 16px !important;
170
+ margin: -16px !important;
171
+ }
172
+
173
+ .InovuaReactDataGrid__header-cell[data-column-id='__checkbox-column'] {
174
+ min-width: 70px !important;
175
+ width: 70px !important;
176
+ max-width: 70px !important;
177
+ padding: 8px 12px !important; /* Reduced padding for compact rows */
178
+ }
179
+
180
+ .InovuaReactDataGrid__header-cell[data-column-id='__checkbox-column']
181
+ input[type='checkbox'] {
182
+ width: 24px !important;
183
+ height: 24px !important;
184
+ }
185
+ }
186
+
187
+ /* Touch device specific improvements - Compact version */
188
+ @media (hover: none) and (pointer: coarse) {
189
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column'] {
190
+ padding: 12px !important; /* Reduced padding for compact rows */
191
+ }
192
+
193
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
194
+ input[type='checkbox'] {
195
+ width: 28px !important;
196
+ height: 28px !important;
197
+ }
198
+
199
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
200
+ .InovuaReactDataGrid__checkbox-wrapper,
201
+ .InovuaReactDataGrid__cell[data-column-id='__checkbox-column']
202
+ .InovuaReactDataGrid__checkbox {
203
+ min-height: 52px !important;
204
+ min-width: 52px !important;
205
+ padding: 18px !important;
206
+ margin: -18px !important;
207
+ }
208
+ }
@@ -228,6 +228,35 @@ input[type]:not([type='search']):not([type='url']):not([type='hidden']):not(
228
228
  max-width: 1200px !important;
229
229
  }
230
230
 
231
+ /* Top-aligned modal styles */
232
+ .modal-top-aligned {
233
+ max-height: 90vh !important;
234
+ overflow-y: auto !important;
235
+ }
236
+
237
+ /* Ensure modal content is scrollable when top-aligned */
238
+ .modal-top-aligned .modal__content {
239
+ max-height: calc(90vh - 60px) !important;
240
+ overflow-y: auto !important;
241
+ }
242
+
243
+ /* Responsive adjustments for top-aligned modals */
244
+ @media (max-width: 768px) {
245
+ .popup-content[style*='top: 5vh'] {
246
+ top: 2vh !important;
247
+ width: 95vw !important;
248
+ max-width: none !important;
249
+ }
250
+
251
+ .modal-top-aligned {
252
+ max-height: 95vh !important;
253
+ }
254
+
255
+ .modal-top-aligned .modal__content {
256
+ max-height: calc(95vh - 60px) !important;
257
+ }
258
+ }
259
+
231
260
  .AutocompletePlace-results {
232
261
  z-index: 999;
233
262
  width: 500px;