@visns-studio/visns-components 5.7.0 → 5.7.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.
@@ -1,36 +1,99 @@
1
1
  .quickActions {
2
2
  width: 100%;
3
- background: rgba(var(--bg-rgb), 0.95);
4
- padding: var(--padding);
5
- border-top: solid 4px rgba(var(--bg-rgb), 1.05);
6
- border-bottom: solid 1px rgba(var(--primary-rgb), 0.25);
3
+ background: rgba(var(--bg-rgb), 0.98);
4
+ padding: 0.75rem var(--padding);
5
+ border-top: solid 3px rgba(var(--primary-rgb), 0.1);
6
+ border-bottom: solid 1px rgba(var(--primary-rgb), 0.15);
7
7
  color: var(--paragraph-color);
8
8
  display: flex;
9
- flex-wrap: nowrap;
9
+ flex-wrap: wrap;
10
10
  align-items: center;
11
- box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
11
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
12
+ overflow: visible; /* Ensure dropdowns are visible */
13
+ position: relative; /* Create a stacking context */
14
+ z-index: 100; /* Ensure proper stacking */
15
+ gap: 0.5rem; /* Add consistent spacing between elements */
16
+
17
+ .actionIcon {
18
+ width: 32px;
19
+ height: 32px;
20
+ display: flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ background-color: rgba(var(--primary-rgb), 0.08);
24
+ border-radius: 50%;
25
+ margin-right: 0.75rem;
26
+ position: relative;
27
+ color: rgba(var(--primary-rgb), 0.8);
28
+ transition: all 0.2s ease;
12
29
 
13
- > span {
14
- width: max-content;
15
- display: block;
16
- font-weight: var(--title-weight);
17
- padding: 0 1rem 0 0;
30
+ &:hover {
31
+ background-color: rgba(var(--primary-rgb), 0.12);
32
+ transform: scale(1.05);
33
+ }
34
+
35
+ &::after {
36
+ content: '';
37
+ position: absolute;
38
+ right: -0.5rem;
39
+ top: 50%;
40
+ transform: translateY(-50%);
41
+ height: 60%;
42
+ width: 1px;
43
+ background-color: rgba(var(--primary-rgb), 0.15);
44
+ }
18
45
  }
19
46
 
20
47
  > button {
21
48
  appearance: none;
22
- border: 1px solid rgba(var(--primary-rgb), 0.25);
23
- border-radius: var(--br);
24
- background: transparent;
49
+ border: 1px solid rgba(var(--primary-rgb), 0.2);
50
+ border-radius: var(--br, 4px);
51
+ background: rgba(var(--bg-rgb), 1);
25
52
  width: max-content;
26
53
  color: var(--paragraph-color);
27
- padding: 0.35rem 0.65rem;
28
- margin: 0 0.25rem;
29
- transition: all 0.25s cubic-bezier(0.25, 0.8, 0.25, 1);
54
+ padding: 0.4rem 0.8rem;
55
+ margin: 0 0.2rem;
56
+ font-size: 0.85rem;
57
+ font-weight: 500;
58
+ transition: all 0.2s ease;
59
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
60
+ display: flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ min-height: 32px;
64
+ position: relative;
65
+ overflow: hidden;
66
+
67
+ &::before {
68
+ content: '';
69
+ position: absolute;
70
+ top: 0;
71
+ left: 0;
72
+ width: 100%;
73
+ height: 100%;
74
+ background: linear-gradient(
75
+ to bottom,
76
+ rgba(var(--primary-rgb), 0.05),
77
+ transparent
78
+ );
79
+ opacity: 0;
80
+ transition: opacity 0.2s ease;
81
+ }
30
82
 
31
83
  &:hover {
32
- background: var(--tertiary-color);
33
- transform: translateY(-2px);
84
+ background: rgba(var(--bg-rgb), 1);
85
+ transform: translateY(-1px);
86
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.08);
87
+ border-color: rgba(var(--primary-rgb), 0.3);
88
+
89
+ &::before {
90
+ opacity: 1;
91
+ }
92
+ }
93
+
94
+ &:active {
95
+ transform: translateY(0);
96
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
34
97
  }
35
98
  }
36
99
 
@@ -38,24 +101,34 @@
38
101
  display: flex;
39
102
  align-items: center;
40
103
  background: transparent;
41
- margin: 0 0.25rem;
104
+ margin-left: auto; /* Push search to the right */
42
105
  flex-grow: 1;
43
106
  position: relative;
107
+ max-width: 300px; /* Limit width for better appearance */
108
+ overflow: visible; /* Allow dropdown to be visible */
44
109
 
45
110
  input[type='text'] {
46
111
  flex-grow: 1;
47
- border: none;
112
+ border: 1px solid rgba(var(--primary-rgb), 0.2);
48
113
  outline: none;
49
- padding: 4px 0.65rem;
50
- padding-right: 30px;
51
- border-radius: var(--br);
114
+ padding: 0.5rem 0.75rem;
115
+ padding-right: 36px;
116
+ border-radius: var(--br, 4px);
52
117
  height: 32px;
53
- font-size: 14px;
118
+ font-size: 0.85rem;
54
119
  width: 100%;
55
- box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
120
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
121
+ transition: all 0.2s ease;
122
+ background-color: rgba(var(--bg-rgb), 1);
123
+
124
+ &::placeholder {
125
+ color: rgba(var(--paragraph-rgb), 0.5);
126
+ font-size: 0.85rem;
127
+ }
56
128
 
57
129
  &:focus {
58
- box-shadow: 0 0 8px rgba(var(--primary-rgb), 0.5);
130
+ box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.15);
131
+ border-color: rgba(var(--primary-rgb), 0.4);
59
132
  }
60
133
  }
61
134
 
@@ -65,35 +138,73 @@
65
138
  display: flex;
66
139
  align-items: center;
67
140
  justify-content: center;
141
+ cursor: pointer;
142
+ width: 24px;
143
+ height: 24px;
144
+ border-radius: 50%;
145
+ transition: background-color 0.2s ease;
146
+
147
+ &:hover {
148
+ background-color: rgba(var(--primary-rgb), 0.05);
149
+ }
68
150
  }
69
151
 
70
152
  .searchIcon {
71
- width: 20px;
72
- height: 20px;
153
+ width: 18px;
154
+ height: 18px;
155
+ color: rgba(var(--paragraph-rgb), 0.6);
156
+ transition: color 0.2s ease;
157
+
158
+ &:hover {
159
+ color: rgba(var(--primary-rgb), 0.8);
160
+ }
73
161
  }
74
162
  }
75
163
 
76
- .searchResults {
164
+ /* Search results styling */
165
+ :global(.AutocompletePlace-results) {
77
166
  position: absolute;
78
167
  top: 100%;
79
168
  width: 100%;
80
- background: var(--third-color);
81
- box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
82
- z-index: 100;
169
+ background: var(--bg-color, white);
170
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
171
+ z-index: 9999; /* Ensure it appears on top */
83
172
  max-height: 400px;
84
173
  overflow-y: auto;
85
- border-radius: var(--br);
86
- margin-top: 5px;
174
+ overflow-x: hidden; /* Prevent horizontal scrolling */
175
+ border-radius: calc(var(--br, 4px) - 1px);
176
+ margin-top: 6px;
177
+ border: 1px solid rgba(var(--primary-rgb), 0.1);
178
+ scrollbar-width: thin;
179
+ scrollbar-color: rgba(var(--primary-rgb), 0.2) transparent;
180
+
181
+ &::-webkit-scrollbar {
182
+ width: 6px;
183
+ }
184
+
185
+ &::-webkit-scrollbar-track {
186
+ background: transparent;
187
+ }
188
+
189
+ &::-webkit-scrollbar-thumb {
190
+ background-color: rgba(var(--primary-rgb), 0.2);
191
+ border-radius: 3px;
192
+ }
87
193
  }
88
194
 
89
195
  .resultItem {
90
- padding: 0.5rem 1rem;
196
+ padding: 0.5rem 0.75rem;
91
197
  cursor: pointer;
92
- transition: background-color 0.3s ease, transform 0.2s ease;
198
+ transition: all 0.15s ease;
199
+ border-bottom: 1px solid rgba(var(--primary-rgb), 0.05);
200
+ white-space: nowrap;
201
+ overflow: hidden;
202
+ text-overflow: ellipsis;
203
+ width: 100%;
93
204
 
94
205
  &:hover {
95
- background-color: #f2f2f2;
96
- transform: translateX(5px);
206
+ background-color: rgba(var(--primary-rgb), 0.05);
207
+ padding-left: 1rem;
97
208
  }
98
209
 
99
210
  &:last-child {
@@ -102,25 +213,36 @@
102
213
 
103
214
  h3 {
104
215
  margin: 0;
105
- font-weight: var(--title-weight);
106
- color: var(--header-color);
107
- font-size: 14px;
216
+ font-weight: 600;
217
+ color: var(--header-color, #333);
218
+ font-size: 0.8rem;
219
+ padding-bottom: 6px;
220
+ border-bottom: 1px solid rgba(var(--primary-rgb), 0.08);
221
+ text-transform: uppercase;
222
+ letter-spacing: 0.03em;
108
223
  }
109
224
 
110
225
  p {
111
226
  margin: 0.25rem 0 0;
112
227
  color: var(--paragraph-color);
113
- font-size: 13px;
228
+ font-size: 0.85rem;
229
+ white-space: nowrap;
230
+ overflow: hidden;
231
+ text-overflow: ellipsis;
232
+ line-height: 1.4;
114
233
  }
115
234
 
116
235
  &.selected {
117
- background-color: rgba(var(--primary-rgb), 0.1);
236
+ background-color: rgba(var(--primary-rgb), 0.08);
237
+ font-weight: 500;
238
+ padding-left: 1rem;
239
+ border-left: 2px solid rgba(var(--primary-rgb), 0.5);
118
240
  }
119
241
  }
120
242
 
121
243
  .resultItemDivider {
122
244
  height: 1px;
123
- background-color: var(--border-color);
124
- margin: 0.25rem 0;
245
+ background-color: rgba(var(--primary-rgb), 0.08);
246
+ margin: 0.25rem 0.75rem;
125
247
  }
126
248
  }
@@ -223,6 +223,11 @@ input[type]:not([type='search']):not([type='url']):not([type='hidden']):not(
223
223
  backdrop-filter: blur(3px);
224
224
  }
225
225
 
226
+ .modalWide {
227
+ width: 80vw !important;
228
+ max-width: 1200px !important;
229
+ }
230
+
226
231
  .AutocompletePlace-results {
227
232
  z-index: 999;
228
233
  width: 500px;
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Fetch utility to replace axios with similar API
3
+ * Designed to work with Laravel backend
4
+ */
5
+
6
+ /**
7
+ * Creates an axios-like response object from a fetch response
8
+ * @param {Response} response - The fetch Response object
9
+ * @param {any} data - The parsed response data
10
+ * @returns {Object} - An axios-like response object
11
+ */
12
+ const createAxiosLikeResponse = async (response, data) => {
13
+ return {
14
+ data,
15
+ status: response.status,
16
+ statusText: response.statusText,
17
+ headers: response.headers,
18
+ config: {
19
+ url: response.url,
20
+ method: response.type,
21
+ },
22
+ request: null, // Not available in fetch
23
+ };
24
+ };
25
+
26
+ /**
27
+ * Main fetch function that mimics axios API
28
+ * @param {Object|string} config - Axios-like config object or URL string
29
+ * @returns {Promise} - Promise that resolves to an axios-like response
30
+ */
31
+ const fetchUtil = async (config) => {
32
+ // Handle string input (URL)
33
+ if (typeof config === 'string') {
34
+ config = { url: config };
35
+ }
36
+
37
+ const {
38
+ url,
39
+ method = 'GET',
40
+ headers = {},
41
+ data,
42
+ params,
43
+ responseType,
44
+ withCredentials = false,
45
+ } = config;
46
+
47
+ // Build request URL with query parameters
48
+ let requestUrl = url;
49
+
50
+ // Create local copies that we can modify
51
+ let paramsObj = params ? { ...params } : {};
52
+ let dataObj = data;
53
+
54
+ // For GET and HEAD requests, convert data to query parameters if it exists
55
+ if (
56
+ (method.toUpperCase() === 'GET' || method.toUpperCase() === 'HEAD') &&
57
+ dataObj &&
58
+ typeof dataObj === 'object' &&
59
+ !(dataObj instanceof FormData)
60
+ ) {
61
+ // Merge data into params
62
+ Object.assign(paramsObj, dataObj);
63
+ // Remove data since we've moved it to params
64
+ dataObj = undefined;
65
+ }
66
+
67
+ // Add params to URL
68
+ if (Object.keys(paramsObj).length > 0) {
69
+ const queryParams = new URLSearchParams();
70
+ Object.entries(paramsObj).forEach(([key, value]) => {
71
+ if (value !== undefined && value !== null) {
72
+ queryParams.append(key, value);
73
+ }
74
+ });
75
+ const queryString = queryParams.toString();
76
+ if (queryString) {
77
+ requestUrl += (url.includes('?') ? '&' : '?') + queryString;
78
+ }
79
+ }
80
+
81
+ // Set up headers
82
+ const requestHeaders = new Headers({
83
+ ...headers,
84
+ });
85
+
86
+ // If not explicitly set and sending data, default to JSON
87
+ if (
88
+ dataObj &&
89
+ !requestHeaders.has('Content-Type') &&
90
+ !(dataObj instanceof FormData)
91
+ ) {
92
+ requestHeaders.set('Content-Type', 'application/json');
93
+ }
94
+
95
+ // Add CSRF token for Laravel if available
96
+ const csrfToken = document
97
+ .querySelector('meta[name="csrf-token"]')
98
+ ?.getAttribute('content');
99
+ if (csrfToken) {
100
+ // Laravel accepts the CSRF token in different headers
101
+ if (!requestHeaders.has('X-CSRF-TOKEN')) {
102
+ requestHeaders.set('X-CSRF-TOKEN', csrfToken);
103
+ }
104
+ if (!requestHeaders.has('X-XSRF-TOKEN')) {
105
+ requestHeaders.set('X-XSRF-TOKEN', csrfToken);
106
+ }
107
+ }
108
+
109
+ // Add X-Requested-With header for Laravel to recognize AJAX requests
110
+ if (!requestHeaders.has('X-Requested-With')) {
111
+ requestHeaders.set('X-Requested-With', 'XMLHttpRequest');
112
+ }
113
+
114
+ // Handle credentials
115
+ const credentials = withCredentials ? 'include' : 'same-origin';
116
+
117
+ // Prepare request options
118
+ const requestOptions = {
119
+ method: method.toUpperCase(),
120
+ headers: requestHeaders,
121
+ credentials,
122
+ };
123
+
124
+ // Add body for non-GET requests
125
+ if (method.toUpperCase() !== 'GET' && method.toUpperCase() !== 'HEAD') {
126
+ // Handle Laravel's _method for PUT/PATCH/DELETE
127
+ if (['PUT', 'PATCH', 'DELETE'].includes(method.toUpperCase())) {
128
+ if (dataObj instanceof FormData) {
129
+ dataObj.append('_method', method.toUpperCase());
130
+ requestOptions.method = 'POST';
131
+ } else if (dataObj && typeof dataObj === 'object') {
132
+ requestOptions.body = JSON.stringify({
133
+ ...dataObj,
134
+ _method: method.toUpperCase(),
135
+ });
136
+ requestOptions.method = 'POST';
137
+ } else {
138
+ // If no data, create a body with just _method
139
+ requestOptions.body = JSON.stringify({
140
+ _method: method.toUpperCase(),
141
+ });
142
+ requestOptions.method = 'POST';
143
+ }
144
+ } else {
145
+ // For regular POST
146
+ if (dataObj instanceof FormData) {
147
+ requestOptions.body = dataObj;
148
+ } else if (dataObj !== undefined) {
149
+ requestOptions.body = JSON.stringify(dataObj);
150
+ }
151
+ }
152
+ }
153
+
154
+ try {
155
+ const response = await fetch(requestUrl, requestOptions);
156
+
157
+ // Parse response based on content type or specified responseType
158
+ let responseData;
159
+
160
+ if (responseType === 'blob') {
161
+ responseData = await response.blob();
162
+ } else if (responseType === 'arraybuffer') {
163
+ responseData = await response.arrayBuffer();
164
+ } else if (responseType === 'text') {
165
+ responseData = await response.text();
166
+ } else {
167
+ // Default: try to parse as JSON, fallback to text
168
+ const contentType = response.headers.get('content-type');
169
+ if (contentType && contentType.includes('application/json')) {
170
+ responseData = await response.json();
171
+ } else {
172
+ responseData = await response.text();
173
+ }
174
+ }
175
+
176
+ const axiosLikeResponse = await createAxiosLikeResponse(
177
+ response,
178
+ responseData
179
+ );
180
+
181
+ // Handle error responses (4xx, 5xx)
182
+ if (!response.ok) {
183
+ const error = new Error(response.statusText || 'Request failed');
184
+ error.response = axiosLikeResponse;
185
+ throw error;
186
+ }
187
+
188
+ return axiosLikeResponse;
189
+ } catch (error) {
190
+ // If the error already has a response property, it's from our code above
191
+ if (!error.response) {
192
+ // Network errors or other fetch errors
193
+ error.response = {
194
+ data: { message: error.message },
195
+ status: 0,
196
+ statusText: error.message,
197
+ };
198
+ }
199
+ throw error;
200
+ }
201
+ };
202
+
203
+ // Add convenience methods to match axios API
204
+ ['get', 'delete', 'head', 'options'].forEach((method) => {
205
+ fetchUtil[method] = (url, config = {}) => {
206
+ // If second parameter is data (object but not a config object with recognized properties)
207
+ if (
208
+ config &&
209
+ typeof config === 'object' &&
210
+ !config.headers &&
211
+ !config.params &&
212
+ !config.responseType &&
213
+ !config.withCredentials
214
+ ) {
215
+ // It's likely data, not config
216
+ return fetchUtil({
217
+ method,
218
+ url,
219
+ params: config, // Use as query parameters
220
+ });
221
+ }
222
+
223
+ return fetchUtil({
224
+ ...config,
225
+ method,
226
+ url,
227
+ });
228
+ };
229
+ });
230
+
231
+ ['post', 'put', 'patch'].forEach((method) => {
232
+ fetchUtil[method] = (url, data, config = {}) => {
233
+ return fetchUtil({
234
+ ...config,
235
+ method,
236
+ url,
237
+ data,
238
+ });
239
+ };
240
+ });
241
+
242
+ export default fetchUtil;