softui-css 1.3.0 → 1.4.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.css CHANGED
@@ -8837,3 +8837,132 @@ a.sui-btn-warning:visited {
8837
8837
  .sui-stat-compact .sui-progress {
8838
8838
  margin-top: 8px;
8839
8839
  }
8840
+
8841
+ /* =========================================
8842
+ Rating
8843
+ ========================================= */
8844
+ .sui-rating {
8845
+ display: inline-flex;
8846
+ align-items: center;
8847
+ gap: 2px;
8848
+ }
8849
+
8850
+ .sui-rating-star {
8851
+ width: 24px;
8852
+ height: 24px;
8853
+ cursor: pointer;
8854
+ color: var(--sui-bg-dark);
8855
+ transition: color 0.15s ease, transform 0.15s ease;
8856
+ flex-shrink: 0;
8857
+ }
8858
+
8859
+ .sui-rating-star svg {
8860
+ width: 100%;
8861
+ height: 100%;
8862
+ fill: currentColor;
8863
+ stroke: none;
8864
+ }
8865
+
8866
+ .sui-rating-star:hover {
8867
+ transform: scale(1.15);
8868
+ }
8869
+
8870
+ .sui-rating-star.active {
8871
+ color: var(--sui-warning);
8872
+ }
8873
+
8874
+ .sui-rating-star.hover {
8875
+ color: var(--sui-warning);
8876
+ opacity: 0.7;
8877
+ }
8878
+
8879
+ .sui-rating-primary .sui-rating-star.hover { color: var(--sui-primary); }
8880
+ .sui-rating-success .sui-rating-star.hover { color: var(--sui-success); }
8881
+ .sui-rating-danger .sui-rating-star.hover { color: var(--sui-danger); }
8882
+ .sui-rating-info .sui-rating-star.hover { color: var(--sui-info); }
8883
+
8884
+ /* Read-only */
8885
+ .sui-rating-readonly .sui-rating-star {
8886
+ cursor: default;
8887
+ }
8888
+
8889
+ .sui-rating-readonly .sui-rating-star:hover {
8890
+ transform: none;
8891
+ }
8892
+
8893
+ /* Half star — uses two layered SVGs: filled (clipped left) + empty (behind) */
8894
+ .sui-rating-star.half,
8895
+ .sui-rating-star.hover-half {
8896
+ position: relative;
8897
+ color: var(--sui-bg-dark);
8898
+ }
8899
+
8900
+ .sui-rating-star.hover-half {
8901
+ opacity: 0.7;
8902
+ }
8903
+
8904
+ .sui-rating-star.half svg:last-child,
8905
+ .sui-rating-star.hover-half svg:last-child {
8906
+ position: absolute;
8907
+ top: 0;
8908
+ left: 0;
8909
+ width: 100%;
8910
+ height: 100%;
8911
+ }
8912
+
8913
+ .sui-rating-star.half svg:first-child,
8914
+ .sui-rating-star.hover-half svg:first-child {
8915
+ clip-path: inset(0 50% 0 0);
8916
+ color: var(--sui-warning);
8917
+ position: relative;
8918
+ z-index: 1;
8919
+ }
8920
+
8921
+ /* Sizes */
8922
+ .sui-rating-sm .sui-rating-star {
8923
+ width: 16px;
8924
+ height: 16px;
8925
+ }
8926
+
8927
+ .sui-rating-sm .sui-rating-star:hover {
8928
+ transform: scale(1.05);
8929
+ }
8930
+
8931
+ .sui-rating-lg .sui-rating-star {
8932
+ width: 32px;
8933
+ height: 32px;
8934
+ }
8935
+
8936
+ /* Colors */
8937
+ .sui-rating-primary .sui-rating-star.active { color: var(--sui-primary); }
8938
+ .sui-rating-primary .sui-rating-star.half svg:first-child { color: var(--sui-primary); }
8939
+ .sui-rating-primary .sui-rating-star.hover-half svg:first-child { color: var(--sui-primary); }
8940
+
8941
+ .sui-rating-success .sui-rating-star.active { color: var(--sui-success); }
8942
+ .sui-rating-success .sui-rating-star.half svg:first-child { color: var(--sui-success); }
8943
+ .sui-rating-success .sui-rating-star.hover-half svg:first-child { color: var(--sui-success); }
8944
+
8945
+ .sui-rating-danger .sui-rating-star.active { color: var(--sui-danger); }
8946
+ .sui-rating-danger .sui-rating-star.half svg:first-child { color: var(--sui-danger); }
8947
+ .sui-rating-danger .sui-rating-star.hover-half svg:first-child { color: var(--sui-danger); }
8948
+
8949
+ .sui-rating-info .sui-rating-star.active { color: var(--sui-info); }
8950
+ .sui-rating-info .sui-rating-star.half svg:first-child { color: var(--sui-info); }
8951
+ .sui-rating-info .sui-rating-star.hover-half svg:first-child { color: var(--sui-info); }
8952
+
8953
+ /* With count */
8954
+ .sui-rating-count {
8955
+ margin-left: 6px;
8956
+ font-size: 13px;
8957
+ color: var(--sui-text-muted);
8958
+ font-weight: 500;
8959
+ }
8960
+
8961
+ /* Inset style */
8962
+ .sui-rating-inset {
8963
+ background: var(--sui-bg);
8964
+ box-shadow: var(--sui-shadow-inset-sm);
8965
+ border-radius: var(--sui-radius);
8966
+ padding: 6px 10px;
8967
+ gap: 4px;
8968
+ }
package/dist/softui.js CHANGED
@@ -2898,5 +2898,90 @@ const SoftUI = (() => {
2898
2898
  return { collapse: collapse, expand: expand, toggle: toggle, isCollapsed: isCollapsed, el: el };
2899
2899
  }
2900
2900
 
2901
+ // =========================================
2902
+ // Rating
2903
+ // =========================================
2904
+ function ratingIsHalf(star, e) {
2905
+ var rect = star.getBoundingClientRect();
2906
+ return e.clientX < rect.left + rect.width / 2;
2907
+ }
2908
+
2909
+ function ratingEnsureDualSvg(star) {
2910
+ var svgs = star.querySelectorAll('svg');
2911
+ if (svgs.length < 2) {
2912
+ var clone = svgs[0].cloneNode(true);
2913
+ star.appendChild(clone);
2914
+ }
2915
+ }
2916
+
2917
+ function ratingResetSvg(star) {
2918
+ var svgs = star.querySelectorAll('svg');
2919
+ if (svgs.length > 1) {
2920
+ for (var i = svgs.length - 1; i > 0; i--) { svgs[i].remove(); }
2921
+ }
2922
+ }
2923
+
2924
+ document.addEventListener('click', function(e) {
2925
+ var star = e.target.closest('.sui-rating:not(.sui-rating-readonly) .sui-rating-star');
2926
+ if (!star) return;
2927
+ var rating = star.closest('.sui-rating');
2928
+ var stars = Array.from(rating.querySelectorAll('.sui-rating-star'));
2929
+ var index = stars.indexOf(star);
2930
+ var allowHalf = rating.classList.contains('sui-rating-half');
2931
+ var isHalf = allowHalf && ratingIsHalf(star, e);
2932
+ var value = isHalf ? index + 0.5 : index + 1;
2933
+ stars.forEach(function(s, i) {
2934
+ s.classList.remove('active', 'half', 'hover', 'hover-half');
2935
+ ratingResetSvg(s);
2936
+ if (i < index) {
2937
+ s.classList.add('active');
2938
+ } else if (i === index) {
2939
+ if (isHalf) {
2940
+ ratingEnsureDualSvg(s);
2941
+ s.classList.add('half');
2942
+ } else {
2943
+ s.classList.add('active');
2944
+ }
2945
+ }
2946
+ });
2947
+ rating.setAttribute('data-value', value);
2948
+ rating.dispatchEvent(new CustomEvent('sui-rating-change', { detail: { value: value } }));
2949
+ });
2950
+
2951
+ document.addEventListener('mousemove', function(e) {
2952
+ var star = e.target.closest('.sui-rating:not(.sui-rating-readonly) .sui-rating-star');
2953
+ if (!star) return;
2954
+ var rating = star.closest('.sui-rating');
2955
+ var stars = Array.from(rating.querySelectorAll('.sui-rating-star'));
2956
+ var index = stars.indexOf(star);
2957
+ var allowHalf = rating.classList.contains('sui-rating-half');
2958
+ var isHalf = allowHalf && ratingIsHalf(star, e);
2959
+ stars.forEach(function(s, i) {
2960
+ s.classList.remove('hover', 'hover-half');
2961
+ ratingResetSvg(s);
2962
+ if (i < index) {
2963
+ s.classList.add('hover');
2964
+ } else if (i === index) {
2965
+ if (isHalf) {
2966
+ ratingEnsureDualSvg(s);
2967
+ s.classList.add('hover-half');
2968
+ } else {
2969
+ s.classList.add('hover');
2970
+ }
2971
+ }
2972
+ });
2973
+ });
2974
+
2975
+ document.addEventListener('mouseout', function(e) {
2976
+ var star = e.target.closest('.sui-rating:not(.sui-rating-readonly) .sui-rating-star');
2977
+ if (!star) return;
2978
+ var rating = star.closest('.sui-rating');
2979
+ var stars = Array.from(rating.querySelectorAll('.sui-rating-star'));
2980
+ stars.forEach(function(s) {
2981
+ s.classList.remove('hover', 'hover-half');
2982
+ if (!s.classList.contains('half')) { ratingResetSvg(s); }
2983
+ });
2984
+ });
2985
+
2901
2986
  return { modal, sheet, toast, carousel, sidebar };
2902
2987
  })();