rails_modal_manager 1.0.34 → 1.0.36

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65672101a104fe19120730ac9bfefc6add2e1e0f3e592b9741c9f83d7ed3a46a
4
- data.tar.gz: 00b57148c22f0ac9b18fea481813facf1020be7f7e36d979faadfc91cbcb4234
3
+ metadata.gz: 1e33e1757e9bc78d6b4e0b801af55ce709813f195254eb3196b8f8394a6afcce
4
+ data.tar.gz: 81818160c6846429dccc642893a95d2c98f0274406aaae378eff2a6e73ff2163
5
5
  SHA512:
6
- metadata.gz: c50a37a75ea2cb8a16edddcd2cd8ad394d8d6e859fa9d735943b64dd71f7509344f17ba9460678eaa9cdaeb89d14828b6678ec617c8cf2d799c2abd31d176b6b
7
- data.tar.gz: 56b5d8e7e1be002a2d926ae4e18e5d7a73ffd0a8518d1714a08cc42dc141ccd0ed17138b4791b68949fc8728e13ea028391a13bd59accf8530d9b905871d3c3f
6
+ metadata.gz: 2b826a9937d346a5163902fd6d6a47ba22816c99ffdcf52710cbe09f3feca7b2bc571b818eb0229f7092fd2615cda1772f7dd01a8a49bf817e454487179b5790
7
+ data.tar.gz: 05bf7a6f7cdbe61b203a44735b597bcd9a57b5fe9eff65b3779eb332cb63ead249118b4175ef52c1f363e0d68726434cc79225e1a540c5d95e0552c1e1917cbc
@@ -23,6 +23,16 @@
23
23
  --rmm-header-text: #1e293b;
24
24
  --rmm-header-height: 56px;
25
25
 
26
+ /* Header - Depth Colors (Parent/Child/Grandchild) */
27
+ --rmm-header-bg-depth-0: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
28
+ --rmm-header-text-depth-0: #ffffff;
29
+ --rmm-header-bg-depth-1: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
30
+ --rmm-header-text-depth-1: #ffffff;
31
+ --rmm-header-bg-depth-2: linear-gradient(135deg, #fc4a1a 0%, #f7b733 100%);
32
+ --rmm-header-text-depth-2: #ffffff;
33
+ --rmm-header-bg-depth-3: linear-gradient(135deg, #ee0979 0%, #ff6a00 100%);
34
+ --rmm-header-text-depth-3: #ffffff;
35
+
26
36
  /* Footer */
27
37
  --rmm-footer-bg: #f8fafc;
28
38
  --rmm-footer-border: rgba(0, 0, 0, 0.1);
@@ -110,6 +120,16 @@
110
120
  --rmm-header-border: rgba(255, 255, 255, 0.1);
111
121
  --rmm-header-text: #f1f5f9;
112
122
 
123
+ /* Header - Depth Colors (Dark Theme) */
124
+ --rmm-header-bg-depth-0: linear-gradient(135deg, #4c51bf 0%, #553c9a 100%);
125
+ --rmm-header-text-depth-0: #ffffff;
126
+ --rmm-header-bg-depth-1: linear-gradient(135deg, #0d7377 0%, #14a085 100%);
127
+ --rmm-header-text-depth-1: #ffffff;
128
+ --rmm-header-bg-depth-2: linear-gradient(135deg, #c0392b 0%, #d68910 100%);
129
+ --rmm-header-text-depth-2: #ffffff;
130
+ --rmm-header-bg-depth-3: linear-gradient(135deg, #a0185e 0%, #c0392b 100%);
131
+ --rmm-header-text-depth-3: #ffffff;
132
+
113
133
  --rmm-footer-bg: #0f172a;
114
134
  --rmm-footer-border: rgba(255, 255, 255, 0.1);
115
135
  --rmm-footer-text: #e2e8f0;
@@ -219,13 +239,18 @@
219
239
  }
220
240
 
221
241
  /* Size variants */
222
- .rmm-modal.rmm-size-fit { width: auto; min-width: 150px; }
223
- .rmm-modal.rmm-size-xss { width: 20%; min-width: 200px; }
224
- .rmm-modal.rmm-size-xs { width: 30%; min-width: 280px; }
225
- .rmm-modal.rmm-size-sm { width: 40%; min-width: 360px; }
226
- .rmm-modal.rmm-size-md { width: 50%; min-width: 480px; }
227
- .rmm-modal.rmm-size-lg { width: 60%; min-width: 600px; }
228
- .rmm-modal.rmm-size-xl { width: 70%; min-width: 720px; }
242
+ /* Modal Size Options (PC)
243
+ - width: 브라우저 크기 대비 비율
244
+ - min-width: 1920px 기준 비율, 단 브라우저보다 커지지 않도록 min() 사용
245
+ - max-width: 브라우저보다 커지지 않도록 제한 (20px 여백 확보)
246
+ */
247
+ .rmm-modal.rmm-size-fit { width: auto; min-width: min(200px, calc(100vw - 40px)); max-width: calc(100vw - 40px); }
248
+ .rmm-modal.rmm-size-xss { width: 20%; min-width: min(384px, calc(100vw - 40px)); max-width: calc(100vw - 40px); } /* 1920 * 20% */
249
+ .rmm-modal.rmm-size-xs { width: 30%; min-width: min(576px, calc(100vw - 40px)); max-width: calc(100vw - 40px); } /* 1920 * 30% */
250
+ .rmm-modal.rmm-size-sm { width: 40%; min-width: min(768px, calc(100vw - 40px)); max-width: calc(100vw - 40px); } /* 1920 * 40% */
251
+ .rmm-modal.rmm-size-md { width: 50%; min-width: min(960px, calc(100vw - 40px)); max-width: calc(100vw - 40px); } /* 1920 * 50% */
252
+ .rmm-modal.rmm-size-lg { width: 60%; min-width: min(1152px, calc(100vw - 40px)); max-width: calc(100vw - 40px); } /* 1920 * 60% */
253
+ .rmm-modal.rmm-size-xl { width: 70%; min-width: min(1344px, calc(100vw - 40px)); max-width: calc(100vw - 40px); } /* 1920 * 70% */
229
254
  .rmm-modal.rmm-size-full,
230
255
  .rmm-modal.rmm-size-full.rmm-active,
231
256
  .rmm-modal.rmm-size-full.rmm-position-center,
@@ -470,6 +495,154 @@
470
495
  white-space: nowrap;
471
496
  }
472
497
 
498
+ /* ============================================
499
+ Modal Depth-based Header Colors
500
+ ============================================ */
501
+ /* Depth 0 - Parent Modal (Purple gradient) */
502
+ .rmm-modal.rmm-depth-0 .rmm-header {
503
+ background: var(--rmm-header-bg-depth-0);
504
+ border-bottom-color: rgba(255, 255, 255, 0.2);
505
+ }
506
+
507
+ .rmm-modal.rmm-depth-0 .rmm-header-title {
508
+ color: var(--rmm-header-text-depth-0);
509
+ }
510
+
511
+ .rmm-modal.rmm-depth-0 .rmm-header-btn {
512
+ color: var(--rmm-header-text-depth-0);
513
+ }
514
+
515
+ .rmm-modal.rmm-depth-0 .rmm-header-btn:hover {
516
+ background: rgba(255, 255, 255, 0.15);
517
+ }
518
+
519
+ .rmm-modal.rmm-depth-0 .rmm-header-btn.rmm-close-btn:hover {
520
+ background: rgba(239, 68, 68, 0.9);
521
+ }
522
+
523
+ .rmm-modal.rmm-depth-0 .rmm-drag-handle {
524
+ color: var(--rmm-header-text-depth-0);
525
+ opacity: 0.6;
526
+ }
527
+
528
+ /* Depth 1 - Child Modal (Green gradient) */
529
+ .rmm-modal.rmm-depth-1 .rmm-header {
530
+ background: var(--rmm-header-bg-depth-1);
531
+ border-bottom-color: rgba(255, 255, 255, 0.2);
532
+ }
533
+
534
+ .rmm-modal.rmm-depth-1 .rmm-header-title {
535
+ color: var(--rmm-header-text-depth-1);
536
+ }
537
+
538
+ .rmm-modal.rmm-depth-1 .rmm-header-btn {
539
+ color: var(--rmm-header-text-depth-1);
540
+ }
541
+
542
+ .rmm-modal.rmm-depth-1 .rmm-header-btn:hover {
543
+ background: rgba(255, 255, 255, 0.15);
544
+ }
545
+
546
+ .rmm-modal.rmm-depth-1 .rmm-header-btn.rmm-close-btn:hover {
547
+ background: rgba(239, 68, 68, 0.9);
548
+ }
549
+
550
+ .rmm-modal.rmm-depth-1 .rmm-drag-handle {
551
+ color: var(--rmm-header-text-depth-1);
552
+ opacity: 0.6;
553
+ }
554
+
555
+ /* Depth 2 - Grandchild Modal (Orange gradient) */
556
+ .rmm-modal.rmm-depth-2 .rmm-header {
557
+ background: var(--rmm-header-bg-depth-2);
558
+ border-bottom-color: rgba(255, 255, 255, 0.2);
559
+ }
560
+
561
+ .rmm-modal.rmm-depth-2 .rmm-header-title {
562
+ color: var(--rmm-header-text-depth-2);
563
+ }
564
+
565
+ .rmm-modal.rmm-depth-2 .rmm-header-btn {
566
+ color: var(--rmm-header-text-depth-2);
567
+ }
568
+
569
+ .rmm-modal.rmm-depth-2 .rmm-header-btn:hover {
570
+ background: rgba(255, 255, 255, 0.15);
571
+ }
572
+
573
+ .rmm-modal.rmm-depth-2 .rmm-header-btn.rmm-close-btn:hover {
574
+ background: rgba(239, 68, 68, 0.9);
575
+ }
576
+
577
+ .rmm-modal.rmm-depth-2 .rmm-drag-handle {
578
+ color: var(--rmm-header-text-depth-2);
579
+ opacity: 0.6;
580
+ }
581
+
582
+ /* Depth 3+ - Deep nested modals (Pink/Red gradient) */
583
+ .rmm-modal.rmm-depth-3 .rmm-header,
584
+ .rmm-modal.rmm-depth-4 .rmm-header,
585
+ .rmm-modal.rmm-depth-5 .rmm-header {
586
+ background: var(--rmm-header-bg-depth-3);
587
+ border-bottom-color: rgba(255, 255, 255, 0.2);
588
+ }
589
+
590
+ .rmm-modal.rmm-depth-3 .rmm-header-title,
591
+ .rmm-modal.rmm-depth-4 .rmm-header-title,
592
+ .rmm-modal.rmm-depth-5 .rmm-header-title {
593
+ color: var(--rmm-header-text-depth-3);
594
+ }
595
+
596
+ .rmm-modal.rmm-depth-3 .rmm-header-btn,
597
+ .rmm-modal.rmm-depth-4 .rmm-header-btn,
598
+ .rmm-modal.rmm-depth-5 .rmm-header-btn {
599
+ color: var(--rmm-header-text-depth-3);
600
+ }
601
+
602
+ .rmm-modal.rmm-depth-3 .rmm-header-btn:hover,
603
+ .rmm-modal.rmm-depth-4 .rmm-header-btn:hover,
604
+ .rmm-modal.rmm-depth-5 .rmm-header-btn:hover {
605
+ background: rgba(255, 255, 255, 0.15);
606
+ }
607
+
608
+ .rmm-modal.rmm-depth-3 .rmm-header-btn.rmm-close-btn:hover,
609
+ .rmm-modal.rmm-depth-4 .rmm-header-btn.rmm-close-btn:hover,
610
+ .rmm-modal.rmm-depth-5 .rmm-header-btn.rmm-close-btn:hover {
611
+ background: rgba(239, 68, 68, 0.9);
612
+ }
613
+
614
+ .rmm-modal.rmm-depth-3 .rmm-drag-handle,
615
+ .rmm-modal.rmm-depth-4 .rmm-drag-handle,
616
+ .rmm-modal.rmm-depth-5 .rmm-drag-handle {
617
+ color: var(--rmm-header-text-depth-3);
618
+ opacity: 0.6;
619
+ }
620
+
621
+ /* ============================================
622
+ Custom Header Colors (via CSS variables)
623
+ Usage: style="--rmm-custom-header-bg: #3b82f6; --rmm-custom-header-text: #ffffff;"
624
+ ============================================ */
625
+ .rmm-modal.rmm-custom-header .rmm-header {
626
+ background: var(--rmm-custom-header-bg, var(--rmm-header-bg));
627
+ border-bottom-color: var(--rmm-custom-header-border, var(--rmm-header-border));
628
+ }
629
+
630
+ .rmm-modal.rmm-custom-header .rmm-header-title {
631
+ color: var(--rmm-custom-header-text, var(--rmm-header-text));
632
+ }
633
+
634
+ .rmm-modal.rmm-custom-header .rmm-header-btn {
635
+ color: var(--rmm-custom-header-text, var(--rmm-header-text));
636
+ }
637
+
638
+ .rmm-modal.rmm-custom-header .rmm-header-btn:hover {
639
+ background: var(--rmm-custom-header-btn-hover, rgba(255, 255, 255, 0.15));
640
+ }
641
+
642
+ .rmm-modal.rmm-custom-header .rmm-drag-handle {
643
+ color: var(--rmm-custom-header-text, var(--rmm-header-text));
644
+ }
645
+
473
646
  /* Size controls dropdown */
474
647
  .rmm-size-controls {
475
648
  position: relative;
@@ -1507,3 +1680,55 @@
1507
1680
  opacity: 0.5;
1508
1681
  transition: opacity 0.2s ease;
1509
1682
  }
1683
+
1684
+ /* ============================================
1685
+ PC Size Fixes (min-width: 769px)
1686
+ - 중간 크기 브라우저에서도 min-width 적용
1687
+ - :not(.rmm-dragging):not(.rmm-custom-position)으로 드래그 중/후 제외
1688
+ ============================================ */
1689
+ @media (min-width: 769px) {
1690
+ /* MD: 769px ~ 960px 범위에서도 min-width 적용 */
1691
+ .rmm-modal.rmm-size-md:not(.rmm-dragging):not(.rmm-custom-position) {
1692
+ width: 50% !important;
1693
+ min-width: min(960px, calc(100vw - 40px)) !important;
1694
+ max-width: calc(100vw - 40px) !important;
1695
+ left: 50% !important;
1696
+ right: auto !important;
1697
+ }
1698
+ .rmm-modal.rmm-size-md.rmm-position-center:not(.rmm-dragging):not(.rmm-custom-position) {
1699
+ transform: translate(-50%, -50%) !important;
1700
+ }
1701
+ .rmm-modal.rmm-size-md.rmm-position-center.rmm-active:not(.rmm-dragging):not(.rmm-custom-position) {
1702
+ transform: translate(-50%, -50%) scale(1) !important;
1703
+ }
1704
+
1705
+ /* LG: 769px ~ 1152px 범위에서도 min-width 적용 */
1706
+ .rmm-modal.rmm-size-lg:not(.rmm-dragging):not(.rmm-custom-position) {
1707
+ width: 60% !important;
1708
+ min-width: min(1152px, calc(100vw - 40px)) !important;
1709
+ max-width: calc(100vw - 40px) !important;
1710
+ left: 50% !important;
1711
+ right: auto !important;
1712
+ }
1713
+ .rmm-modal.rmm-size-lg.rmm-position-center:not(.rmm-dragging):not(.rmm-custom-position) {
1714
+ transform: translate(-50%, -50%) !important;
1715
+ }
1716
+ .rmm-modal.rmm-size-lg.rmm-position-center.rmm-active:not(.rmm-dragging):not(.rmm-custom-position) {
1717
+ transform: translate(-50%, -50%) scale(1) !important;
1718
+ }
1719
+
1720
+ /* XL: 769px ~ 1344px 범위에서도 min-width 적용 */
1721
+ .rmm-modal.rmm-size-xl:not(.rmm-dragging):not(.rmm-custom-position) {
1722
+ width: 70% !important;
1723
+ min-width: min(1344px, calc(100vw - 40px)) !important;
1724
+ max-width: calc(100vw - 40px) !important;
1725
+ left: 50% !important;
1726
+ right: auto !important;
1727
+ }
1728
+ .rmm-modal.rmm-size-xl.rmm-position-center:not(.rmm-dragging):not(.rmm-custom-position) {
1729
+ transform: translate(-50%, -50%) !important;
1730
+ }
1731
+ .rmm-modal.rmm-size-xl.rmm-position-center.rmm-active:not(.rmm-dragging):not(.rmm-custom-position) {
1732
+ transform: translate(-50%, -50%) scale(1) !important;
1733
+ }
1734
+ }
@@ -37,6 +37,10 @@ export default class extends Controller {
37
37
  confirmClose: { type: Boolean, default: false },
38
38
  confirmCloseMessage: { type: String, default: "정말 닫으시겠습니까?" },
39
39
  mobileDefaultMaximized: { type: Boolean, default: false },
40
+ // Custom header colors
41
+ headerBg: String, // Custom header background color (e.g., "#3b82f6" or "linear-gradient(135deg, #667eea, #764ba2)")
42
+ headerText: String, // Custom header text color (e.g., "#ffffff")
43
+ headerBorder: String, // Custom header border color (e.g., "#2563eb")
40
44
  }
41
45
 
42
46
  connect() {
@@ -328,6 +332,9 @@ export default class extends Controller {
328
332
  // Apply initial size and position
329
333
  this.applyStyles()
330
334
 
335
+ // Apply depth class for visual hierarchy (parent/child/grandchild)
336
+ this.applyDepthClass()
337
+
331
338
  // Start animation
332
339
  requestAnimationFrame(() => {
333
340
  modal.classList.add('rmm-active')
@@ -340,6 +347,46 @@ export default class extends Controller {
340
347
  })
341
348
  }
342
349
 
350
+ /**
351
+ * Apply depth-based CSS class for visual hierarchy
352
+ * Depth 0 (root): rmm-depth-0
353
+ * Depth 1 (child): rmm-depth-1
354
+ * Depth 2 (grandchild): rmm-depth-2
355
+ * Depth 3+ (great-grandchild): rmm-depth-3
356
+ *
357
+ * Also applies custom header colors if specified via data attributes
358
+ */
359
+ applyDepthClass() {
360
+ const modal = this.element
361
+ const modalId = this.effectiveModalId
362
+ const depth = modalStore.getModalDepth(modalId)
363
+
364
+ // Remove existing depth classes
365
+ modal.classList.remove('rmm-depth-0', 'rmm-depth-1', 'rmm-depth-2', 'rmm-depth-3')
366
+
367
+ // Check for custom header colors
368
+ const hasCustomHeader = this.hasHeaderBgValue || this.hasHeaderTextValue || this.hasHeaderBorderValue
369
+
370
+ if (hasCustomHeader) {
371
+ // Apply custom header colors via CSS variables
372
+ modal.classList.add('rmm-custom-header')
373
+
374
+ if (this.hasHeaderBgValue && this.headerBgValue) {
375
+ modal.style.setProperty('--rmm-custom-header-bg', this.headerBgValue)
376
+ }
377
+ if (this.hasHeaderTextValue && this.headerTextValue) {
378
+ modal.style.setProperty('--rmm-custom-header-text', this.headerTextValue)
379
+ }
380
+ if (this.hasHeaderBorderValue && this.headerBorderValue) {
381
+ modal.style.setProperty('--rmm-custom-header-border', this.headerBorderValue)
382
+ }
383
+ } else {
384
+ // Apply depth class (only if no custom header colors)
385
+ const depthClass = `rmm-depth-${Math.min(depth, 3)}`
386
+ modal.classList.add(depthClass)
387
+ }
388
+ }
389
+
343
390
  hideModal(callback) {
344
391
  const modal = this.element
345
392
  const overlay = this.getOverlay()
@@ -347,10 +394,18 @@ export default class extends Controller {
347
394
  // Reset sidebar and submenu to first item before hiding
348
395
  this.resetSidebarAndSubmenu()
349
396
 
397
+ // 닫기 애니메이션 시작 (현재 위치에서 닫힘)
350
398
  modal.classList.remove('rmm-active')
351
399
  if (overlay) overlay.classList.remove('rmm-active')
352
400
 
353
401
  setTimeout(() => {
402
+ // 애니메이션 완료 후 드래그로 인한 커스텀 위치 클래스 및 인라인 스타일 제거
403
+ modal.classList.remove('rmm-custom-position')
404
+ modal.classList.remove('rmm-dragging')
405
+ modal.style.top = ''
406
+ modal.style.left = ''
407
+ modal.style.transform = ''
408
+
354
409
  // Reset openValue to false so modal can be reopened
355
410
  // Use a flag to prevent openValueChanged from triggering close again
356
411
  this._closingProgrammatically = true
@@ -417,17 +472,34 @@ export default class extends Controller {
417
472
 
418
473
  // For full size, explicitly set full screen styles
419
474
  if (config.size === 'full' || config.isMaximized) {
420
- modal.style.width = '100%'
421
- modal.style.height = '100%'
422
- modal.style.minWidth = '100%'
423
- modal.style.maxHeight = '100%'
424
- modal.style.top = '0'
425
- modal.style.left = '0'
426
- modal.style.right = '0'
427
- modal.style.bottom = '0'
428
- modal.style.transform = 'none'
429
- modal.style.borderRadius = '0'
430
- modal.style.margin = '0'
475
+ // 최소화된 모달이 있는지 store에서 확인하여 taskbar 높이 계산
476
+ const minimizedGroups = modalStore.getMinimizedModalGroups()
477
+ const hasMinimizedModals = minimizedGroups.length > 0
478
+ // CSS 변수에서 taskbar 높이 가져오기 (기본값 48px)
479
+ const taskbarHeight = hasMinimizedModals
480
+ ? parseInt(getComputedStyle(document.documentElement).getPropertyValue('--rmm-taskbar-height') || '48', 10)
481
+ : 0
482
+
483
+ // CSS !important를 덮어쓰기 위해 setProperty 사용
484
+ modal.style.setProperty('width', '100%', 'important')
485
+ modal.style.setProperty('min-width', '100%', 'important')
486
+ modal.style.setProperty('top', '0', 'important')
487
+ modal.style.setProperty('left', '0', 'important')
488
+ modal.style.setProperty('right', '0', 'important')
489
+ modal.style.setProperty('transform', 'none', 'important')
490
+ modal.style.setProperty('border-radius', '0', 'important')
491
+ modal.style.setProperty('margin', '0', 'important')
492
+
493
+ if (taskbarHeight > 0) {
494
+ // taskbar가 있으면 그 위까지만 표시
495
+ modal.style.setProperty('height', `calc(100% - ${taskbarHeight}px)`, 'important')
496
+ modal.style.setProperty('max-height', `calc(100% - ${taskbarHeight}px)`, 'important')
497
+ modal.style.setProperty('bottom', `${taskbarHeight}px`, 'important')
498
+ } else {
499
+ modal.style.setProperty('height', '100%', 'important')
500
+ modal.style.setProperty('max-height', '100%', 'important')
501
+ modal.style.setProperty('bottom', '0', 'important')
502
+ }
431
503
  } else {
432
504
  // Reset full-size specific styles
433
505
  modal.style.borderRadius = ''
@@ -548,6 +620,7 @@ export default class extends Controller {
548
620
  historyStackManager.moveToTop('modal', this.effectiveModalId)
549
621
  }
550
622
  this.isDragging = true
623
+ this.element.classList.add('rmm-dragging')
551
624
 
552
625
  const clientX = e.type.includes('touch') ? e.touches[0].clientX : e.clientX
553
626
  const clientY = e.type.includes('touch') ? e.touches[0].clientY : e.clientY
@@ -590,6 +663,9 @@ export default class extends Controller {
590
663
 
591
664
  handleDragEnd() {
592
665
  this.isDragging = false
666
+ this.element.classList.remove('rmm-dragging')
667
+ // 드래그 후 위치 유지를 위해 custom-position 클래스 추가
668
+ this.element.classList.add('rmm-custom-position')
593
669
 
594
670
  this.element.style.transition = ''
595
671
 
@@ -23,14 +23,16 @@ export const MODAL_CONSTANTS = {
23
23
  export const CASCADE_OFFSET = { x: 30, y: 30 };
24
24
 
25
25
  // Size configurations (matching React version)
26
+ // min-width: 1920px 기준 비율 적용 (브라우저가 작아져도 이 이하로 줄어들지 않음)
27
+ // max-width는 CSS에서 calc(100vw - 40px)로 처리하여 브라우저 벗어남 방지
26
28
  export const SIZE_CONFIG = {
27
- fit: { width: 'auto', minWidth: '150px', height: 'auto' },
28
- xss: { width: '20%', minWidth: '200px', height: 'auto' },
29
- xs: { width: '30%', minWidth: '280px', height: 'auto' },
30
- sm: { width: '40%', minWidth: '360px', height: 'auto' },
31
- md: { width: '50%', minWidth: '480px', height: 'auto' },
32
- lg: { width: '60%', minWidth: '600px', height: 'auto' },
33
- xl: { width: '70%', minWidth: '720px', height: 'auto' },
29
+ fit: { width: 'auto', minWidth: '200px', height: 'auto' },
30
+ xss: { width: '20%', minWidth: '384px', height: 'auto' }, // 1920 * 20%
31
+ xs: { width: '30%', minWidth: '576px', height: 'auto' }, // 1920 * 30%
32
+ sm: { width: '40%', minWidth: '768px', height: 'auto' }, // 1920 * 40%
33
+ md: { width: '50%', minWidth: '960px', height: 'auto' }, // 1920 * 50%
34
+ lg: { width: '60%', minWidth: '1152px', height: 'auto' }, // 1920 * 60%
35
+ xl: { width: '70%', minWidth: '1344px', height: 'auto' }, // 1920 * 70%
34
36
  full: { width: '100%', minWidth: '100%', height: '100%' },
35
37
  };
36
38
 
@@ -490,6 +492,20 @@ class ModalStore {
490
492
  return [...this.getModalChain(config.parentModalId), modalId];
491
493
  }
492
494
 
495
+ /**
496
+ * Get the depth of a modal in the parent-child hierarchy
497
+ * Root modals (no parent) have depth 0, children have depth 1, grandchildren depth 2, etc.
498
+ * @param {string} modalId - The modal ID to get depth for
499
+ * @returns {number} The depth level (0 for root, 1 for child, 2 for grandchild, etc.)
500
+ */
501
+ getModalDepth(modalId) {
502
+ const config = this.activeModals[modalId];
503
+ if (!config || !config.parentModalId) {
504
+ return 0;
505
+ }
506
+ return 1 + this.getModalDepth(config.parentModalId);
507
+ }
508
+
493
509
  getModalGroupSize(modalId) {
494
510
  const rootId = this.getRootModal(modalId);
495
511
  const descendants = this.getAllDescendants(rootId);
@@ -42,6 +42,9 @@
42
42
  footer_buttons: Array - Footer buttons (default: [])
43
43
  extra_class: String - Additional CSS classes (default: "")
44
44
  extra_data: Hash - Additional data attributes (default: {})
45
+ header_bg: String - Custom header background (e.g., "#3b82f6" or "linear-gradient(135deg, #667eea, #764ba2)")
46
+ header_text: String - Custom header text color (e.g., "#ffffff")
47
+ header_border: String - Custom header border color (e.g., "#2563eb")
45
48
  %>
46
49
  <%
47
50
  # Default values
@@ -86,6 +89,9 @@
86
89
  extra_class ||= ""
87
90
  extra_data ||= {}
88
91
  mobile_default_maximized ||= false
92
+ header_bg ||= nil
93
+ header_text ||= nil
94
+ header_border ||= nil
89
95
 
90
96
  # Build CSS classes
91
97
  modal_classes = ["rmm-modal", "rmm-size-#{size}", "rmm-position-#{position}"]
@@ -122,6 +128,9 @@
122
128
  data_attrs[:rmm_modal_persistent_id_value] = persistent_id if persistent_id
123
129
  data_attrs[:rmm_modal_max_width_value] = max_width if max_width
124
130
  data_attrs[:rmm_modal_max_height_value] = max_height if max_height
131
+ data_attrs[:rmm_modal_header_bg_value] = header_bg if header_bg
132
+ data_attrs[:rmm_modal_header_text_value] = header_text if header_text
133
+ data_attrs[:rmm_modal_header_border_value] = header_border if header_border
125
134
  data_attrs.merge!(extra_data)
126
135
  %>
127
136
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsModalManager
4
- VERSION = "1.0.34"
4
+ VERSION = "1.0.36"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_modal_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.34
4
+ version: 1.0.36
5
5
  platform: ruby
6
6
  authors:
7
7
  - reshacs