softui-css 1.5.0 → 1.6.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.
package/dist/softui.js CHANGED
@@ -3645,5 +3645,282 @@ const SoftUI = (() => {
3645
3645
  });
3646
3646
  }, true);
3647
3647
 
3648
+ // =========================================
3649
+ // Image Lightbox
3650
+ // =========================================
3651
+ var lightboxOverlay = null;
3652
+ var lightboxImages = [];
3653
+ var lightboxIndex = 0;
3654
+
3655
+ function createLightbox() {
3656
+ if (lightboxOverlay) return;
3657
+ lightboxOverlay = document.createElement('div');
3658
+ lightboxOverlay.className = 'sui-lightbox-overlay';
3659
+ lightboxOverlay.innerHTML =
3660
+ '<button class="sui-lightbox-close" aria-label="Close">&times;</button>' +
3661
+ '<span class="sui-lightbox-counter"></span>' +
3662
+ '<button class="sui-lightbox-prev" aria-label="Previous"><svg viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg></button>' +
3663
+ '<button class="sui-lightbox-next" aria-label="Next"><svg viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></button>' +
3664
+ '<img src="" alt="">' +
3665
+ '<div class="sui-lightbox-caption"></div>';
3666
+ document.body.appendChild(lightboxOverlay);
3667
+
3668
+ lightboxOverlay.querySelector('.sui-lightbox-close').addEventListener('click', closeLightbox);
3669
+ lightboxOverlay.querySelector('.sui-lightbox-prev').addEventListener('click', function() { showLightboxImage(lightboxIndex - 1); });
3670
+ lightboxOverlay.querySelector('.sui-lightbox-next').addEventListener('click', function() { showLightboxImage(lightboxIndex + 1); });
3671
+ lightboxOverlay.addEventListener('click', function(e) {
3672
+ if (e.target === lightboxOverlay) closeLightbox();
3673
+ if (e.target.tagName === 'IMG') {
3674
+ lightboxOverlay.classList.toggle('zoomed');
3675
+ }
3676
+ });
3677
+ document.addEventListener('keydown', function(e) {
3678
+ if (!lightboxOverlay || !lightboxOverlay.classList.contains('open')) return;
3679
+ if (e.key === 'Escape') closeLightbox();
3680
+ if (e.key === 'ArrowLeft') showLightboxImage(lightboxIndex - 1);
3681
+ if (e.key === 'ArrowRight') showLightboxImage(lightboxIndex + 1);
3682
+ });
3683
+ }
3684
+
3685
+ function openLightbox(images, index) {
3686
+ createLightbox();
3687
+ lightboxImages = images;
3688
+ lightboxIndex = index || 0;
3689
+ showLightboxImage(lightboxIndex);
3690
+ lightboxOverlay.classList.add('open');
3691
+ lightboxOverlay.classList.remove('zoomed');
3692
+ document.body.style.overflow = 'hidden';
3693
+ var hasMultiple = images.length > 1;
3694
+ lightboxOverlay.querySelector('.sui-lightbox-prev').style.display = hasMultiple ? '' : 'none';
3695
+ lightboxOverlay.querySelector('.sui-lightbox-next').style.display = hasMultiple ? '' : 'none';
3696
+ lightboxOverlay.querySelector('.sui-lightbox-counter').style.display = hasMultiple ? '' : 'none';
3697
+ }
3698
+
3699
+ function closeLightbox() {
3700
+ if (lightboxOverlay) {
3701
+ lightboxOverlay.classList.remove('open', 'zoomed');
3702
+ document.body.style.overflow = '';
3703
+ }
3704
+ }
3705
+
3706
+ function showLightboxImage(idx) {
3707
+ if (lightboxImages.length === 0) return;
3708
+ lightboxIndex = (idx + lightboxImages.length) % lightboxImages.length;
3709
+ var item = lightboxImages[lightboxIndex];
3710
+ var img = lightboxOverlay.querySelector('img');
3711
+ var caption = lightboxOverlay.querySelector('.sui-lightbox-caption');
3712
+ var counter = lightboxOverlay.querySelector('.sui-lightbox-counter');
3713
+ img.src = item.src;
3714
+ img.alt = item.alt || '';
3715
+ caption.textContent = item.caption || '';
3716
+ caption.style.display = item.caption ? '' : 'none';
3717
+ counter.textContent = (lightboxIndex + 1) + ' / ' + lightboxImages.length;
3718
+ lightboxOverlay.classList.remove('zoomed');
3719
+ }
3720
+
3721
+ // Vertical gallery — click side thumb to update main
3722
+ document.addEventListener('click', function(e) {
3723
+ var thumb = e.target.closest('.sui-lightbox-vertical-strip .sui-lightbox-thumb');
3724
+ if (!thumb) return;
3725
+ var gallery = thumb.closest('.sui-lightbox-vertical');
3726
+ var main = gallery.querySelector('.sui-lightbox-vertical-main img');
3727
+ var img = thumb.querySelector('img');
3728
+ if (main && img) {
3729
+ main.src = thumb.getAttribute('data-src') || img.src;
3730
+ main.alt = thumb.getAttribute('data-alt') || img.alt;
3731
+ }
3732
+ gallery.querySelectorAll('.sui-lightbox-vertical-strip .sui-lightbox-thumb').forEach(function(t) { t.classList.remove('active'); });
3733
+ thumb.classList.add('active');
3734
+ });
3735
+
3736
+ // Click main image in vertical gallery to open lightbox
3737
+ document.addEventListener('click', function(e) {
3738
+ var main = e.target.closest('.sui-lightbox-vertical-main');
3739
+ if (!main) return;
3740
+ var gallery = main.closest('.sui-lightbox-vertical');
3741
+ var thumbs = Array.from(gallery.querySelectorAll('.sui-lightbox-vertical-strip .sui-lightbox-thumb'));
3742
+ var images = thumbs.map(function(t) {
3743
+ var img = t.querySelector('img');
3744
+ return {
3745
+ src: t.getAttribute('data-src') || (img ? img.src : ''),
3746
+ alt: t.getAttribute('data-alt') || (img ? img.alt : ''),
3747
+ caption: t.getAttribute('data-caption') || ''
3748
+ };
3749
+ });
3750
+ var activeIdx = thumbs.findIndex(function(t) { return t.classList.contains('active'); });
3751
+ openLightbox(images, activeIdx >= 0 ? activeIdx : 0);
3752
+ });
3753
+
3754
+ // Click on thumbnail
3755
+ document.addEventListener('click', function(e) {
3756
+ var thumb = e.target.closest('.sui-lightbox-thumb');
3757
+ if (!thumb) return;
3758
+ // Skip if inside vertical strip (handled above)
3759
+ if (thumb.closest('.sui-lightbox-vertical-strip')) return;
3760
+ var grid = thumb.closest('.sui-lightbox-grid');
3761
+ var thumbs = grid ? Array.from(grid.querySelectorAll('.sui-lightbox-thumb')) : [thumb];
3762
+ var images = thumbs.map(function(t) {
3763
+ var img = t.querySelector('img');
3764
+ return {
3765
+ src: t.getAttribute('data-src') || (img ? img.src : ''),
3766
+ alt: t.getAttribute('data-alt') || (img ? img.alt : ''),
3767
+ caption: t.getAttribute('data-caption') || ''
3768
+ };
3769
+ });
3770
+ var index = thumbs.indexOf(thumb);
3771
+ openLightbox(images, index);
3772
+ });
3773
+
3774
+ // =========================================
3775
+ // Diff — Image Compare Slider
3776
+ // =========================================
3777
+ function initDiffSliders() {
3778
+ document.querySelectorAll('.sui-diff[data-sui-diff]').forEach(function(diff) {
3779
+ if (diff.dataset.suiDiffInit) return;
3780
+ diff.dataset.suiDiffInit = '1';
3781
+ var handle = diff.querySelector('.sui-diff-handle');
3782
+ var before = diff.querySelector('.sui-diff-before');
3783
+ if (!handle || !before) return;
3784
+ var isVertical = diff.classList.contains('sui-diff-vertical');
3785
+
3786
+ function onMove(e) {
3787
+ e.preventDefault();
3788
+ var rect = diff.getBoundingClientRect();
3789
+ var pos;
3790
+ if (isVertical) {
3791
+ var clientY = e.touches ? e.touches[0].clientY : e.clientY;
3792
+ pos = Math.max(0, Math.min(1, (clientY - rect.top) / rect.height));
3793
+ var pct = (pos * 100);
3794
+ before.style.clipPath = 'inset(0 0 ' + (100 - pct) + '% 0)';
3795
+ handle.style.top = pct + '%';
3796
+ } else {
3797
+ var clientX = e.touches ? e.touches[0].clientX : e.clientX;
3798
+ pos = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
3799
+ var pct = (pos * 100);
3800
+ before.style.clipPath = 'inset(0 ' + (100 - pct) + '% 0 0)';
3801
+ handle.style.left = pct + '%';
3802
+ }
3803
+ }
3804
+
3805
+ function onDown(e) {
3806
+ e.preventDefault();
3807
+ onMove(e);
3808
+ document.addEventListener('mousemove', onMove);
3809
+ document.addEventListener('mouseup', onUp);
3810
+ document.addEventListener('touchmove', onMove, { passive: false });
3811
+ document.addEventListener('touchend', onUp);
3812
+ }
3813
+
3814
+ function onUp() {
3815
+ document.removeEventListener('mousemove', onMove);
3816
+ document.removeEventListener('mouseup', onUp);
3817
+ document.removeEventListener('touchmove', onMove);
3818
+ document.removeEventListener('touchend', onUp);
3819
+ }
3820
+
3821
+ diff.addEventListener('mousedown', onDown);
3822
+ diff.addEventListener('touchstart', onDown, { passive: false });
3823
+ });
3824
+ }
3825
+
3826
+ if (document.readyState === 'loading') {
3827
+ document.addEventListener('DOMContentLoaded', initDiffSliders);
3828
+ } else {
3829
+ initDiffSliders();
3830
+ }
3831
+
3832
+ // =========================================
3833
+ // Speed Dial
3834
+ // =========================================
3835
+ document.addEventListener('click', function(e) {
3836
+ var trigger = e.target.closest('.sui-speed-dial-trigger');
3837
+ if (trigger) {
3838
+ var dial = trigger.closest('.sui-speed-dial');
3839
+ dial.classList.toggle('open');
3840
+ return;
3841
+ }
3842
+ var action = e.target.closest('.sui-speed-dial-action');
3843
+ if (action) {
3844
+ var dial = action.closest('.sui-speed-dial');
3845
+ dial.classList.remove('open');
3846
+ return;
3847
+ }
3848
+ // Close all open dials when clicking outside
3849
+ document.querySelectorAll('.sui-speed-dial.open').forEach(function(d) {
3850
+ d.classList.remove('open');
3851
+ });
3852
+ });
3853
+
3854
+ // Hover mode
3855
+ document.addEventListener('mouseenter', function(e) {
3856
+ var dial = e.target.closest('.sui-speed-dial-hover');
3857
+ if (dial) dial.classList.add('open');
3858
+ }, true);
3859
+
3860
+ document.addEventListener('mouseleave', function(e) {
3861
+ var dial = e.target.closest('.sui-speed-dial-hover');
3862
+ if (dial) dial.classList.remove('open');
3863
+ }, true);
3864
+
3865
+ // =========================================
3866
+ // Tree View
3867
+ // =========================================
3868
+ document.addEventListener('click', function(e) {
3869
+ var label = e.target.closest('.sui-tree-label');
3870
+ if (!label) return;
3871
+ if (e.target.closest('.sui-checkbox')) return;
3872
+ var item = label.closest('.sui-tree-item');
3873
+ var children = item.querySelector('.sui-tree-children');
3874
+ if (children) {
3875
+ item.classList.toggle('expanded');
3876
+ }
3877
+ });
3878
+
3879
+ // Tree checkbox propagation
3880
+ document.addEventListener('change', function(e) {
3881
+ if (!e.target.closest('.sui-tree .sui-checkbox input')) return;
3882
+ var checkbox = e.target;
3883
+ var item = checkbox.closest('.sui-tree-item');
3884
+ var checked = checkbox.checked;
3885
+
3886
+ // Propagate down — check/uncheck all children
3887
+ var childBoxes = item.querySelectorAll('.sui-tree-children .sui-checkbox input');
3888
+ childBoxes.forEach(function(cb) {
3889
+ cb.checked = checked;
3890
+ cb.indeterminate = false;
3891
+ });
3892
+
3893
+ // Propagate up — update parent state
3894
+ updateTreeParent(item);
3895
+ });
3896
+
3897
+ function updateTreeParent(item) {
3898
+ var parentChildren = item.closest('.sui-tree-children');
3899
+ if (!parentChildren) return;
3900
+ var parentItem = parentChildren.closest('.sui-tree-item');
3901
+ if (!parentItem) return;
3902
+ var parentCb = parentItem.querySelector(':scope > .sui-tree-label .sui-checkbox input');
3903
+ if (!parentCb) return;
3904
+
3905
+ var siblings = parentChildren.querySelectorAll(':scope > .sui-tree-item > .sui-tree-label .sui-checkbox input');
3906
+ var total = siblings.length;
3907
+ var checkedCount = 0;
3908
+ siblings.forEach(function(cb) { if (cb.checked) checkedCount++; });
3909
+
3910
+ if (checkedCount === 0) {
3911
+ parentCb.checked = false;
3912
+ parentCb.indeterminate = false;
3913
+ } else if (checkedCount === total) {
3914
+ parentCb.checked = true;
3915
+ parentCb.indeterminate = false;
3916
+ } else {
3917
+ parentCb.checked = false;
3918
+ parentCb.indeterminate = true;
3919
+ }
3920
+
3921
+ // Continue up the tree
3922
+ updateTreeParent(parentItem);
3923
+ }
3924
+
3648
3925
  return { modal, sheet, toast, carousel, sidebar };
3649
3926
  })();