@visns-studio/visns-components 5.11.8 → 5.11.10

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
@@ -16,7 +16,7 @@
16
16
  "@uiw/react-color": "^2.6.0",
17
17
  "@visns-studio/visns-datagrid-community": "^1.0.14",
18
18
  "@visns-studio/visns-datagrid-enterprise": "^1.0.14",
19
- "@vitejs/plugin-react": "^4.5.2",
19
+ "@vitejs/plugin-react": "^4.6.0",
20
20
  "add": "^2.0.6",
21
21
  "array-move": "^4.0.0",
22
22
  "awesome-debounce-promise": "^2.1.0",
@@ -87,7 +87,7 @@
87
87
  "react-dom": "^17.0.0 || ^18.0.0"
88
88
  },
89
89
  "name": "@visns-studio/visns-components",
90
- "version": "5.11.8",
90
+ "version": "5.11.10",
91
91
  "description": "Various packages to assist in the development of our Custom Applications.",
92
92
  "main": "src/index.js",
93
93
  "files": [
@@ -549,10 +549,10 @@ function Field({
549
549
  );
550
550
  case 'async-dropdown-ajax':
551
551
  return (
552
- <div className={styles.dropdownContainer}>
552
+ <div className={`${styles.dropdownContainer} ${settings.create ? styles.hasButton : ''}`}>
553
553
  <VisnsAsyncSelect
554
554
  settings={settings}
555
- className={inputClass[settings.id]}
555
+ className={`${inputClass[settings.id]} ${settings.create ? styles.selectFullWidth : ''}`}
556
556
  multi={
557
557
  settings.hasOwnProperty('multi')
558
558
  ? settings.multi
@@ -568,6 +568,35 @@ function Field({
568
568
  dataOptions={dataOptions}
569
569
  isCreatable={settings.isCreatable || false}
570
570
  />
571
+ {settings.create && (
572
+ <button
573
+ className={styles.buttonRight}
574
+ onClick={(e) => {
575
+ e.preventDefault();
576
+ let allow = false;
577
+
578
+ if (settings.create.parent_id) {
579
+ if (
580
+ formData[settings.create.parent_id]
581
+ ) {
582
+ allow = true;
583
+ }
584
+ } else {
585
+ allow = true;
586
+ }
587
+
588
+ if (allow) {
589
+ handleAddEntry(settings.create);
590
+ } else {
591
+ toast.warning(
592
+ 'Please select a parent item first'
593
+ );
594
+ }
595
+ }}
596
+ >
597
+ <CirclePlus strokeWidth={2} size={16} />
598
+ </button>
599
+ )}
571
600
  </div>
572
601
  );
573
602
  case 'canvas':
@@ -778,7 +807,7 @@ function Field({
778
807
  case 'dropdown':
779
808
  case 'dropdown-ajax':
780
809
  return (
781
- <div className={styles.dropdownContainer}>
810
+ <div className={`${styles.dropdownContainer} ${settings.create ? styles.hasButton : ''}`}>
782
811
  <Select
783
812
  settings={settings}
784
813
  className={
@@ -1287,7 +1316,7 @@ function Field({
1287
1316
  case 'multi-dropdown':
1288
1317
  case 'multi-dropdown-ajax':
1289
1318
  return (
1290
- <div className={styles.dropdownContainer}>
1319
+ <div className={`${styles.dropdownContainer} ${settings.create ? styles.hasButton : ''}`}>
1291
1320
  <MultiSelect
1292
1321
  settings={settings}
1293
1322
  className={
@@ -2257,8 +2286,178 @@ function Field({
2257
2286
  }
2258
2287
  };
2259
2288
 
2260
- const handleReload = () => {
2289
+ const handleReload = (createdItem = null) => {
2261
2290
  setCounter(counter + 1);
2291
+
2292
+ // Auto-select the newly created item if provided
2293
+ if (createdItem && onChange) {
2294
+ console.log('Auto-selecting created item:', createdItem);
2295
+
2296
+ // Analyze existing options to understand the expected format
2297
+ const analyzeOptionsFormat = () => {
2298
+ let existingOptions = [];
2299
+
2300
+ // Get options based on dropdown type
2301
+ if (['dropdown', 'multi-dropdown'].includes(settings.type) && settings.options) {
2302
+ existingOptions = settings.options;
2303
+ } else if (['dropdown-ajax', 'multi-dropdown-ajax', 'async-dropdown-ajax'].includes(settings.type) && options) {
2304
+ existingOptions = options;
2305
+ }
2306
+
2307
+ if (existingOptions.length === 0) return null;
2308
+
2309
+ // Analyze the first few options to understand the label pattern
2310
+ const sampleOption = existingOptions[0];
2311
+ return {
2312
+ hasLabel: !!sampleOption.label,
2313
+ hasName: !!sampleOption.name,
2314
+ hasFirstname: !!(sampleOption.firstname || sampleOption.surname),
2315
+ hasTitle: !!sampleOption.title,
2316
+ hasDescription: !!sampleOption.description,
2317
+ labelPattern: sampleOption.label || sampleOption.name || 'name'
2318
+ };
2319
+ };
2320
+
2321
+ const formatAnalysis = analyzeOptionsFormat();
2322
+
2323
+ // Determine the label for the created item based on existing options format or common patterns
2324
+ const getItemLabel = (item) => {
2325
+ // If we have format analysis, try to match the existing pattern
2326
+ if (formatAnalysis) {
2327
+ if (formatAnalysis.hasLabel && item.label) return item.label;
2328
+ if (formatAnalysis.hasName && item.name) return item.name;
2329
+ if (formatAnalysis.hasFirstname && (item.firstname || item.surname)) {
2330
+ return `${item.firstname || ''} ${item.surname || ''}`.trim();
2331
+ }
2332
+ if (formatAnalysis.hasTitle && item.title) return item.title;
2333
+ if (formatAnalysis.hasDescription && item.description) return item.description;
2334
+ }
2335
+
2336
+ // Fallback to common patterns
2337
+ if (item.label) return item.label;
2338
+ if (item.name) return item.name;
2339
+ if (item.firstname || item.surname) {
2340
+ return `${item.firstname || ''} ${item.surname || ''}`.trim();
2341
+ }
2342
+ if (item.title) return item.title;
2343
+ if (item.description) return item.description;
2344
+ return `Item ${item.id}`;
2345
+ };
2346
+
2347
+ const itemLabel = getItemLabel(createdItem);
2348
+
2349
+ // Create a properly formatted item for MultiSelect/Select components
2350
+ // Match the format of existing options as closely as possible
2351
+ const formattedItem = {
2352
+ id: createdItem.id,
2353
+ value: createdItem.id,
2354
+ label: itemLabel,
2355
+ ...createdItem // Preserve all original properties
2356
+ };
2357
+
2358
+ console.log('Format analysis:', formatAnalysis);
2359
+ console.log('Formatted item for selection:', formattedItem);
2360
+
2361
+ // For different dropdown types, handle the selection appropriately
2362
+ if (['dropdown', 'dropdown-ajax'].includes(settings.type)) {
2363
+ // For single select fields
2364
+ if (onChangeSelect) {
2365
+ onChangeSelect(formattedItem, { name: settings.id });
2366
+ }
2367
+ // Also update form data with the ID for single selects
2368
+ if (setFormData) {
2369
+ setFormData((prevState) => ({
2370
+ ...prevState,
2371
+ [settings.id]: createdItem.id
2372
+ }));
2373
+ }
2374
+ } else if (['multi-dropdown', 'multi-dropdown-ajax', 'async-dropdown-ajax'].includes(settings.type)) {
2375
+ // For multi-select fields, we need to handle existing selections
2376
+ if (onChangeSelect) {
2377
+ // Get current value to determine if it's multi-select
2378
+ const currentValue = inputValue || [];
2379
+ let newValue;
2380
+
2381
+ if (settings.hasOwnProperty('multi') && settings.multi === false) {
2382
+ // Single select in multi-dropdown component
2383
+ newValue = formattedItem;
2384
+ } else {
2385
+ // True multi-select - add to existing selections
2386
+ const currentArray = Array.isArray(currentValue) ? currentValue :
2387
+ (currentValue ? [currentValue] : []);
2388
+
2389
+ // Check if item already exists (avoid duplicates)
2390
+ const existsIndex = currentArray.findIndex(item =>
2391
+ (item.id && item.id === createdItem.id) ||
2392
+ (item.value && item.value === createdItem.id)
2393
+ );
2394
+
2395
+ if (existsIndex === -1) {
2396
+ // Add new item to the array
2397
+ newValue = [...currentArray, formattedItem];
2398
+ } else {
2399
+ // Replace existing item
2400
+ newValue = [...currentArray];
2401
+ newValue[existsIndex] = formattedItem;
2402
+ }
2403
+ }
2404
+
2405
+ onChangeSelect(newValue, { name: settings.id });
2406
+ }
2407
+
2408
+ // Update form data with the appropriate format
2409
+ if (setFormData) {
2410
+ setFormData((prevState) => {
2411
+ const currentValue = prevState[settings.id] || [];
2412
+ const currentArray = Array.isArray(currentValue) ? currentValue :
2413
+ (currentValue ? [currentValue] : []);
2414
+
2415
+ // Check if we're in multi mode
2416
+ if (settings.hasOwnProperty('multi') && settings.multi === false) {
2417
+ return {
2418
+ ...prevState,
2419
+ [settings.id]: formattedItem
2420
+ };
2421
+ } else {
2422
+ // Check for duplicates
2423
+ const existsIndex = currentArray.findIndex(item =>
2424
+ (item.id && item.id === createdItem.id) ||
2425
+ (item.value && item.value === createdItem.id)
2426
+ );
2427
+
2428
+ let newArray;
2429
+ if (existsIndex === -1) {
2430
+ newArray = [...currentArray, formattedItem];
2431
+ } else {
2432
+ newArray = [...currentArray];
2433
+ newArray[existsIndex] = formattedItem;
2434
+ }
2435
+
2436
+ return {
2437
+ ...prevState,
2438
+ [settings.id]: newArray
2439
+ };
2440
+ }
2441
+ });
2442
+ }
2443
+ } else {
2444
+ // For regular input fields, use onChange
2445
+ const syntheticEvent = {
2446
+ target: {
2447
+ dataset: { name: settings.id },
2448
+ value: createdItem.id
2449
+ }
2450
+ };
2451
+ onChange(syntheticEvent);
2452
+
2453
+ if (setFormData) {
2454
+ setFormData((prevState) => ({
2455
+ ...prevState,
2456
+ [settings.id]: createdItem.id
2457
+ }));
2458
+ }
2459
+ }
2460
+ }
2262
2461
  };
2263
2462
 
2264
2463
  useEffect(() => {
@@ -2294,6 +2493,8 @@ function Field({
2294
2493
  open={childFormShow}
2295
2494
  onClose={childFormClose}
2296
2495
  closeOnDocumentClick={false}
2496
+ overlayStyle={{ zIndex: 10001 }}
2497
+ contentStyle={{ zIndex: 10002 }}
2297
2498
  >
2298
2499
  <Form
2299
2500
  ajaxSetting={childForm.ajaxSetting}
@@ -2309,12 +2510,15 @@ function Field({
2309
2510
  paramValue={null}
2310
2511
  style={style}
2311
2512
  updateForm={setChildForm}
2513
+ userProfile={userProfile}
2312
2514
  />
2313
2515
  </Popup>
2314
2516
  <Popup
2315
2517
  open={canvasPopupOpen}
2316
2518
  onClose={() => setCanvasPopupOpen(false)}
2317
2519
  closeOnDocumentClick={false}
2520
+ overlayStyle={{ zIndex: 10001 }}
2521
+ contentStyle={{ zIndex: 10002 }}
2318
2522
  >
2319
2523
  <div className={`${styles.modalwrap} ${styles['top--modal']}`}>
2320
2524
  <div className={styles.modal}>
@@ -1068,7 +1068,11 @@ function Form({
1068
1068
  location.reload();
1069
1069
  }, 1000);
1070
1070
  }
1071
- if (fetchTable) fetchTable();
1071
+ if (fetchTable) {
1072
+ // Pass the created item data to fetchTable for auto-selection
1073
+ const createdItem = res.data.data || res.data;
1074
+ fetchTable(createdItem);
1075
+ }
1072
1076
  if (closeModal) {
1073
1077
  closeModal();
1074
1078
  if (type === 'saveAnother') {
@@ -1107,7 +1111,10 @@ function Form({
1107
1111
 
1108
1112
  if (resSaveAnother.data.error === '') {
1109
1113
  toast.success(saveAnother.message);
1110
- fetchTable();
1114
+ if (fetchTable) {
1115
+ const createdItem = res.data.data || res.data;
1116
+ fetchTable(createdItem);
1117
+ }
1111
1118
  }
1112
1119
  } else {
1113
1120
  fetchData();
@@ -62,6 +62,43 @@ const CustomMultiValue = (props) => {
62
62
  );
63
63
  };
64
64
 
65
+ // Custom MultiValueRemove component with debug logging
66
+ const CustomMultiValueRemove = (props) => {
67
+ const { innerProps, data } = props;
68
+
69
+ return (
70
+ <components.MultiValueRemove
71
+ {...props}
72
+ innerProps={{
73
+ ...innerProps,
74
+ onClick: (e) => {
75
+ console.log('MultiSelect: Remove button clicked for item:', data);
76
+ console.log('MultiSelect: Event details:', e);
77
+
78
+ // Prevent event bubbling
79
+ e.stopPropagation();
80
+ e.preventDefault();
81
+
82
+ // Call the original handler
83
+ if (innerProps && innerProps.onClick) {
84
+ console.log('MultiSelect: Calling original onClick handler');
85
+ innerProps.onClick(e);
86
+ } else {
87
+ console.log('MultiSelect: No original onClick handler found');
88
+ }
89
+ },
90
+ onMouseDown: (e) => {
91
+ console.log('MultiSelect: Remove button mouse down');
92
+ e.stopPropagation();
93
+ if (innerProps && innerProps.onMouseDown) {
94
+ innerProps.onMouseDown(e);
95
+ }
96
+ }
97
+ }}
98
+ />
99
+ );
100
+ };
101
+
65
102
  function MultiSelect({
66
103
  className,
67
104
  inputValue = [], // Default to an empty array
@@ -230,12 +267,22 @@ function MultiSelect({
230
267
  SelectList,
231
268
  Option: CustomOption,
232
269
  MultiValue: (props) => <CustomMultiValue {...props} settings={settings} />,
270
+ MultiValueRemove: CustomMultiValueRemove,
233
271
  }}
234
272
  options={selectOptions}
235
273
  menuPortalTarget={document.body}
236
274
  menuPlacement={menuPlacement}
237
275
  onMenuOpen={handleMenuOpen}
238
276
  onChange={(inputValue, action) => {
277
+ // Debug logging for delete actions
278
+ if (action.action === 'remove-value') {
279
+ console.log('MultiSelect: Individual item delete:', {
280
+ removedValue: action.removedValue,
281
+ newValue: inputValue,
282
+ action: action
283
+ });
284
+ }
285
+
239
286
  // Special handling for limit=1: keep only the most recent selection
240
287
  if (
241
288
  settings.limit === 1 &&
@@ -333,7 +380,7 @@ function MultiSelect({
333
380
  flex: '1',
334
381
  minWidth: '0',
335
382
  }),
336
- multiValueRemove: (base) => ({
383
+ multiValueRemove: (base, state) => ({
337
384
  ...base,
338
385
  padding: '0 4px',
339
386
  display: 'flex',
@@ -341,12 +388,12 @@ function MultiSelect({
341
388
  justifyContent: 'center',
342
389
  margin: '0',
343
390
  borderRadius: '0 4px 4px 0',
344
- backgroundColor: 'transparent',
345
- transition: 'background-color 0.2s ease',
346
- '&:hover': {
347
- backgroundColor: '#dc2626',
348
- color: 'white',
349
- },
391
+ backgroundColor: state.isFocused ? '#dc2626' : 'transparent',
392
+ color: state.isFocused ? 'white' : '#666',
393
+ transition: 'all 0.2s ease',
394
+ cursor: 'pointer',
395
+ minWidth: '16px',
396
+ minHeight: '16px',
350
397
  }),
351
398
  }}
352
399
  value={selectValue}
@@ -408,7 +408,21 @@ const QuickAction = ({ setting }) => {
408
408
  </div>
409
409
  </div>
410
410
 
411
- <Popup open={modalShow} onClose={modalClose}>
411
+ <Popup
412
+ open={modalShow}
413
+ onClose={modalClose}
414
+ closeOnDocumentClick={false}
415
+ contentStyle={{
416
+ width: '80vw',
417
+ maxWidth: '1200px',
418
+ minWidth: '600px',
419
+ padding: 0,
420
+ border: 'none',
421
+ borderRadius: '8px',
422
+ overflow: 'hidden',
423
+ maxHeight: '90vh',
424
+ }}
425
+ >
412
426
  <Form
413
427
  closeModal={modalClose}
414
428
  fetchTable={() => {}}
@@ -1355,7 +1355,7 @@ function GenericDashboard({ setting, userProfile, dynamicDashboard = false }) {
1355
1355
  )}
1356
1356
  <div className={styles.grid} ref={container}>
1357
1357
  {renderWidgets()}
1358
- <Popup open={modalShow} onClose={closeModal}>
1358
+ <Popup open={modalShow} onClose={closeModal} closeOnDocumentClick={false}>
1359
1359
  <div className="modalwrap top--modal modalWide">
1360
1360
  <div className="modal">
1361
1361
  <div className="modal__header">
@@ -20,6 +20,54 @@ import SortableTableBody from './SortableQuoteItems';
20
20
 
21
21
  import styles from './styles/GenericQuote.module.scss';
22
22
 
23
+ // Isolated Proposal Preview Component
24
+ function ProposalPreviewFrame({ content }) {
25
+ const iframeRef = React.useRef(null);
26
+
27
+ React.useEffect(() => {
28
+ if (iframeRef.current && content) {
29
+ const iframe = iframeRef.current;
30
+ const doc = iframe.contentDocument || iframe.contentWindow.document;
31
+
32
+ // Write the complete HTML document to iframe
33
+ doc.open();
34
+ doc.write(content);
35
+ doc.close();
36
+
37
+ // Optional: Add responsive styling to iframe body
38
+ const style = doc.createElement('style');
39
+ style.textContent = `
40
+ body {
41
+ margin: 0;
42
+ padding: 20px;
43
+ font-family: Arial, sans-serif;
44
+ background: white;
45
+ overflow-x: auto;
46
+ }
47
+ * {
48
+ box-sizing: border-box;
49
+ }
50
+ `;
51
+ doc.head.appendChild(style);
52
+ }
53
+ }, [content]);
54
+
55
+ return (
56
+ <iframe
57
+ ref={iframeRef}
58
+ className={styles.proposalPreview}
59
+ title="Proposal Preview"
60
+ sandbox="allow-same-origin"
61
+ style={{
62
+ width: '100%',
63
+ height: '100%',
64
+ border: 'none',
65
+ background: 'white'
66
+ }}
67
+ />
68
+ );
69
+ }
70
+
23
71
  function GenericQuote({ logo, setting, urlParam, proposalConfig = null }) {
24
72
  const routeParams = useParams();
25
73
  const navigate = useNavigate();
@@ -835,7 +883,7 @@ function GenericQuote({ logo, setting, urlParam, proposalConfig = null }) {
835
883
  proposal_section_type: data.proposal_section_type || 'content',
836
884
  },
837
885
  template_id: parseInt(selectedTemplate),
838
- filename: `proposal-${data.id || 'draft'}-${new Date().toISOString().split('T')[0]}.pdf`,
886
+ filename: `${(data.customer?.name || 'Customer').replace(/[/\\?%*:|"<>]/g, '-')} - Proposal #${data.id || 'draft'} - ${(data.label || 'Quote').replace(/[/\\?%*:|"<>]/g, '-')}.pdf`,
839
887
  download: true,
840
888
  paper: 'a4',
841
889
  orientation: 'portrait'
@@ -844,7 +892,7 @@ function GenericQuote({ logo, setting, urlParam, proposalConfig = null }) {
844
892
  // Create a form for file download
845
893
  const form = document.createElement('form');
846
894
  form.method = 'POST';
847
- form.action = '/ajax/pdf/generate-proposal';
895
+ form.action = `/ajax/quotes/${data.id}/generate-proposal`;
848
896
  form.style.display = 'none';
849
897
 
850
898
  // Add CSRF token
@@ -1454,10 +1502,7 @@ function GenericQuote({ logo, setting, urlParam, proposalConfig = null }) {
1454
1502
  <X size={16} aria-hidden="true" />
1455
1503
  </button>
1456
1504
  </div>
1457
- <div
1458
- className={styles.proposalPreview}
1459
- dangerouslySetInnerHTML={{ __html: proposalPreview }}
1460
- />
1505
+ <ProposalPreviewFrame content={proposalPreview} />
1461
1506
  </div>
1462
1507
  )}
1463
1508
 
@@ -179,8 +179,10 @@
179
179
  border: 1px solid #e9ecef;
180
180
  border-radius: 8px;
181
181
  background: white;
182
- max-height: 1200px; /* Double the previous height */
183
- overflow: hidden;
182
+ height: auto;
183
+ min-height: 1100px;
184
+ max-height: none; /* Remove height restriction */
185
+ overflow: visible; /* Allow content to be visible */
184
186
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
185
187
  }
186
188
 
@@ -213,225 +215,16 @@
213
215
  }
214
216
 
215
217
  .proposalPreview {
216
- /* Container styles - only affect this container */
217
- padding: 20px;
218
- overflow-y: auto;
219
- overflow-x: hidden;
220
- max-height: 1000px;
218
+ /* Iframe container styles - content is completely isolated */
219
+ width: 100% !important;
220
+ height: 1000px !important;
221
+ min-height: 1000px !important;
222
+ max-height: none !important;
221
223
  background: white;
222
224
  box-sizing: border-box;
223
- position: relative;
224
-
225
- /* Isolate content styles using descendant selectors */
226
-
227
- /* Reset and apply clean typography for proposal content */
228
- & * {
229
- font-family: inherit;
230
- color: inherit;
231
- }
232
-
233
- /* Base content styling */
234
- font-family: 'Times', 'Times New Roman', serif;
235
- font-size: 14px;
236
- line-height: 1.6;
237
- color: #333;
238
-
239
- /* Headings */
240
- & h1, & h2, & h3, & h4, & h5, & h6 {
241
- font-family: 'Arial', 'Helvetica', sans-serif;
242
- font-weight: bold;
243
- color: #333;
244
- margin-top: 0;
245
- margin-bottom: 15px;
246
- line-height: 1.2;
247
- }
248
-
249
- & h1 {
250
- font-size: 28px;
251
- margin-bottom: 20px;
252
- margin-top: 0;
253
- }
254
- & h2 {
255
- font-size: 24px;
256
- margin-top: 30px;
257
- margin-bottom: 15px;
258
- }
259
- & h3 {
260
- font-size: 20px;
261
- margin-top: 25px;
262
- margin-bottom: 12px;
263
- }
264
- & h4 { font-size: 18px; margin-bottom: 12px; }
265
- & h5 { font-size: 16px; margin-bottom: 10px; }
266
- & h6 { font-size: 14px; margin-bottom: 10px; }
267
-
268
- /* Paragraphs and text */
269
- & p {
270
- font-family: 'Times', 'Times New Roman', serif;
271
- font-size: 14px;
272
- line-height: 1.6;
273
- margin: 0 0 12px 0;
274
- color: #333;
275
- }
276
-
277
- /* Page breaks */
278
- & .page-break, & [style*="page-break"] {
279
- margin-top: 40px;
280
- padding-top: 40px;
281
- border-top: 2px dashed #ccc;
282
- }
283
-
284
- /* Tables */
285
- & table {
286
- width: 100%;
287
- border-collapse: collapse;
288
- margin: 15px 0;
289
- font-family: 'Arial', 'Helvetica', sans-serif;
290
- border: 2px solid #333333;
291
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
292
-
293
- & th, & td {
294
- padding: 14px;
295
- border: 1px solid #333333;
296
- text-align: left;
297
- font-size: 14px;
298
- line-height: 1.4;
299
- color: #333;
300
- vertical-align: middle;
301
- }
302
-
303
- & th {
304
- background: #4fbfa5 !important;
305
- color: white !important;
306
- font-weight: bold;
307
- }
308
-
309
- & td {
310
- background: white;
311
- font-weight: 500;
312
- }
313
-
314
- & tr:nth-child(even) td {
315
- background: #f9f9f9;
316
- }
317
-
318
- & tfoot tr {
319
- background: #f3f4f6;
320
-
321
- & td {
322
- font-weight: bold;
323
- border-top: 2px solid #333333;
324
- }
325
-
326
- &:last-child {
327
- background: #333333 !important;
328
-
329
- & td {
330
- color: white !important;
331
- font-weight: bold;
332
- }
333
- }
334
- }
335
- }
336
-
337
- /* Lists */
338
- & ul, & ol {
339
- font-family: 'Times', 'Times New Roman', serif;
340
- font-size: 14px;
341
- line-height: 1.6;
342
- margin: 12px 0;
343
- padding-left: 25px;
344
- color: #333;
345
-
346
- & li {
347
- margin: 8px 0;
348
- color: #333;
349
- }
350
- }
351
-
352
- /* Text formatting */
353
- & strong, & b {
354
- font-weight: bold;
355
- }
356
-
357
- & em, & i {
358
- font-style: italic;
359
- }
360
-
361
- /* Images */
362
- & img {
363
- max-width: 100%;
364
- height: auto;
365
- margin: 10px 0;
366
- }
367
-
368
- /* Divs and sections */
369
- & div {
370
- margin-bottom: 0;
371
- }
372
-
373
- /* Override any branding classes that might interfere */
374
- & .primary-bg, & .secondary-bg, & .accent-bg,
375
- & .primary-text, & .secondary-text, & .accent-text {
376
- color: #333 !important;
377
- background: transparent !important;
378
- }
379
-
380
- /* Terms and conditions specific styling */
381
- & .terms-section, & .terms-conditions-section, & [class*="terms"] {
382
- margin: 20px 0;
383
- padding: 15px;
384
- border: 1px solid #ddd;
385
- background: #f9f9f9;
386
-
387
- & h1, & h2, & h3, & h4 {
388
- margin-top: 15px;
389
- margin-bottom: 10px;
390
- color: #333;
391
-
392
- &:first-child {
393
- margin-top: 0;
394
- }
395
- }
396
-
397
- & h1 {
398
- font-size: 24px;
399
- border-bottom: 2px solid #333;
400
- padding-bottom: 10px;
401
- }
402
-
403
- & h3 {
404
- font-size: 16px;
405
- margin-top: 20px;
406
- }
407
-
408
- & p {
409
- white-space: pre-wrap;
410
- word-wrap: break-word;
411
- margin-bottom: 12px;
412
- text-align: justify;
413
- hyphens: auto;
414
- }
415
-
416
- & .terms-content {
417
- max-width: none;
418
- overflow: visible;
419
- }
420
- }
421
-
422
- /* Ensure all content is visible and not truncated */
423
- & * {
424
- max-height: none !important;
425
- overflow: visible !important;
426
- text-overflow: clip !important;
427
- }
428
-
429
- /* Special handling for long content */
430
- & div, & section {
431
- overflow: visible;
432
- height: auto;
433
- max-height: none;
434
- }
225
+ border: none;
226
+ border-radius: 4px;
227
+ display: block !important;
435
228
  }
436
229
 
437
230
  /* Content Editor Styles */
@@ -1419,12 +1212,18 @@
1419
1212
  background-color: #f3f4f6;
1420
1213
  }
1421
1214
 
1215
+ .subtotalLabel,
1216
+ .subtotalValue {
1217
+ color: #333 !important;
1218
+ }
1219
+
1422
1220
  &:last-child {
1423
1221
  background-color: #333333 !important;
1424
1222
 
1425
1223
  .subtotalLabel,
1426
1224
  .subtotalValue {
1427
1225
  color: white !important;
1226
+ background-color: #333333 !important;
1428
1227
  }
1429
1228
  }
1430
1229
  }
@@ -1436,6 +1235,7 @@
1436
1235
  color: #374151;
1437
1236
  font-size: 14px;
1438
1237
  border: 1px solid #333333;
1238
+ background: inherit;
1439
1239
  }
1440
1240
 
1441
1241
  .subtotalValue {
@@ -1446,6 +1246,7 @@
1446
1246
  font-size: 14px;
1447
1247
  white-space: nowrap;
1448
1248
  border: 1px solid #333333;
1249
+ background: inherit;
1449
1250
  }
1450
1251
 
1451
1252
  /* Responsive styles */
@@ -20,8 +20,9 @@
20
20
  border-radius: var(--br, 8px);
21
21
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
22
22
  overflow: hidden;
23
- max-width: 95vw;
24
- width: 800px;
23
+ width: 80vw;
24
+ max-width: 1200px;
25
+ min-width: 600px;
25
26
  max-height: 90vh;
26
27
  display: flex;
27
28
  flex-direction: column;
@@ -3,28 +3,118 @@
3
3
  width: 100%;
4
4
  }
5
5
 
6
+ /* Only apply flex layout when there's a create button */
7
+ .dropdownContainer:has(.buttonRight) {
8
+ display: flex;
9
+ align-items: stretch;
10
+ }
11
+
6
12
  .selectFullWidth {
7
13
  width: 90%;
8
14
  }
9
15
 
16
+ /* Only style the select when there's a create button */
17
+ .dropdownContainer:has(.buttonRight) .selectFullWidth {
18
+ flex: 1;
19
+ width: auto;
20
+ border-top-right-radius: 0;
21
+ border-bottom-right-radius: 0;
22
+ }
23
+
24
+ /* Ensure the select component inside container integrates seamlessly - only when button exists */
25
+ .dropdownContainer:has(.buttonRight) .selectFullWidth > div,
26
+ .dropdownContainer:has(.buttonRight) .selectFullWidth .visns-select__control,
27
+ .dropdownContainer:has(.buttonRight) .selectFullWidth select {
28
+ border-top-right-radius: 0 !important;
29
+ border-bottom-right-radius: 0 !important;
30
+ border-right: none !important;
31
+ }
32
+
33
+ .dropdownContainer:has(.buttonRight) .selectFullWidth .visns-select__control--is-focused,
34
+ .dropdownContainer:has(.buttonRight) .selectFullWidth select:focus {
35
+ border-right: none !important;
36
+ box-shadow: none !important;
37
+ }
38
+
39
+ /* Ensure consistent height between select and button */
40
+ .dropdownContainer:has(.buttonRight) .selectFullWidth select {
41
+ height: auto;
42
+ min-height: 3.1rem; /* Match typical input height */
43
+ }
44
+
10
45
  .buttonRight {
46
+ display: flex;
47
+ align-items: center;
48
+ justify-content: center;
49
+ min-width: 42px;
50
+ min-height: 3.1rem;
51
+ background: rgba(var(--primary-color-rgb), 0.08);
52
+ color: var(--primary-color);
53
+ border: 1px solid rgba(var(--primary-color-rgb), 0.25);
54
+ border-left: none;
55
+ border-top-right-radius: var(--br);
56
+ border-bottom-right-radius: var(--br);
57
+ cursor: pointer;
58
+ transition: all 0.2s ease;
59
+ outline: none;
60
+ padding: 0;
61
+ position: relative;
62
+ }
63
+
64
+ .buttonRight::before {
65
+ content: '';
11
66
  position: absolute;
12
- right: 0;
13
- top: 50%;
14
- transform: translateY(-50%);
15
- z-index: 1;
67
+ top: 20%;
68
+ left: 0;
69
+ width: 1px;
70
+ height: 60%;
71
+ background: rgba(var(--primary-color-rgb), 0.15);
72
+ }
73
+
74
+ .buttonRight:hover {
16
75
  background: var(--primary-color);
17
76
  color: var(--secondary-color);
18
- padding: 1rem 0.5rem;
19
- border: none;
20
- border-radius: var(--br);
21
- cursor: pointer;
22
- transition: background 0.3s;
77
+ border-color: var(--primary-color);
23
78
  }
24
79
 
25
- .buttonRight:hover {
26
- background: var(--secondary-color);
27
- color: var(--primary-color);
80
+ .buttonRight:hover::before {
81
+ display: none;
82
+ }
83
+
84
+ .buttonRight:focus {
85
+ box-shadow: 0 0 0 2px rgba(var(--primary-color-rgb), 0.2);
86
+ }
87
+
88
+ /* Fallback for browsers that don't support :has() */
89
+ .dropdownContainer.hasButton {
90
+ display: flex;
91
+ align-items: stretch;
92
+ }
93
+
94
+ .dropdownContainer.hasButton .selectFullWidth {
95
+ flex: 1;
96
+ width: auto;
97
+ border-top-right-radius: 0;
98
+ border-bottom-right-radius: 0;
99
+ }
100
+
101
+ .dropdownContainer.hasButton .selectFullWidth > div,
102
+ .dropdownContainer.hasButton .selectFullWidth .visns-select__control,
103
+ .dropdownContainer.hasButton .selectFullWidth select {
104
+ border-top-right-radius: 0 !important;
105
+ border-bottom-right-radius: 0 !important;
106
+ border-right: none !important;
107
+ }
108
+
109
+ .dropdownContainer.hasButton .selectFullWidth .visns-select__control--is-focused,
110
+ .dropdownContainer.hasButton .selectFullWidth select:focus {
111
+ border-right: none !important;
112
+ box-shadow: none !important;
113
+ }
114
+
115
+ .dropdownContainer.hasButton .selectFullWidth select {
116
+ height: auto;
117
+ min-height: 3.1rem;
28
118
  }
29
119
 
30
120
  .formcontainer {
@@ -158,12 +158,33 @@
158
158
  margin: 0 !important;
159
159
  border-radius: 0 4px 4px 0 !important;
160
160
  background-color: transparent !important;
161
- transition: background-color 0.2s ease !important;
161
+ transition: all 0.2s ease !important;
162
+ cursor: pointer !important;
163
+ pointer-events: auto !important;
164
+ position: relative !important;
165
+ z-index: 10 !important;
166
+ min-width: 20px !important;
167
+ min-height: 20px !important;
168
+ border: 1px solid transparent !important;
162
169
  }
163
170
 
164
171
  .visns-select__multi-value__remove:hover {
165
172
  background-color: #dc2626 !important;
166
173
  color: white !important;
174
+ border-color: #dc2626 !important;
175
+ }
176
+
177
+ .visns-select__multi-value__remove:focus {
178
+ background-color: #dc2626 !important;
179
+ color: white !important;
180
+ border-color: #dc2626 !important;
181
+ outline: none !important;
182
+ }
183
+
184
+ .visns-select__multi-value__remove:active {
185
+ background-color: #b91c1c !important;
186
+ color: white !important;
187
+ transform: scale(0.95) !important;
167
188
  }
168
189
 
169
190
  /* Fix for modals */