@orangesk/orange-design-system 2.0.0-beta.43 → 2.0.0-beta.45

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.
Files changed (60) hide show
  1. package/build/components/BodyBanner/style.css +1 -1
  2. package/build/components/BodyBanner/style.css.map +1 -1
  3. package/build/components/Breadcrumbs/style.css +1 -1
  4. package/build/components/Breadcrumbs/style.css.map +1 -1
  5. package/build/components/Carousel/style.css +1 -1
  6. package/build/components/Carousel/style.css.map +1 -1
  7. package/build/components/Expander/style.css +1 -1
  8. package/build/components/Expander/style.css.map +1 -1
  9. package/build/components/Footer/style.css +1 -1
  10. package/build/components/Footer/style.css.map +1 -1
  11. package/build/components/Grid/style.css +1 -1
  12. package/build/components/Grid/style.css.map +1 -1
  13. package/build/components/Megamenu/style.css +1 -1
  14. package/build/components/Megamenu/style.css.map +1 -1
  15. package/build/components/Tag/style.css +1 -1
  16. package/build/components/Tag/style.css.map +1 -1
  17. package/build/components/index.js +1 -1
  18. package/build/components/index.js.map +1 -1
  19. package/build/components/tsconfig.tsbuildinfo +1 -1
  20. package/build/components/types/index.d.ts +4 -2
  21. package/build/components/types/src/components/Carousel/Carousel.static.d.ts +7 -0
  22. package/build/components/types/src/components/Expander/Expander.d.ts +2 -0
  23. package/build/components/types/src/components/Grid/Grid.d.ts +2 -2
  24. package/build/lib/base.css +1 -1
  25. package/build/lib/base.css.map +1 -1
  26. package/build/lib/components.css +1 -1
  27. package/build/lib/components.css.map +1 -1
  28. package/build/lib/footer.css +1 -1
  29. package/build/lib/footer.css.map +1 -1
  30. package/build/lib/megamenu.css +1 -1
  31. package/build/lib/megamenu.css.map +1 -1
  32. package/build/lib/scripts.js +1 -1
  33. package/build/lib/scripts.js.map +1 -1
  34. package/build/lib/style.css +1 -1
  35. package/build/lib/style.css.map +1 -1
  36. package/build/search-index.json +2 -2
  37. package/build/sprite.svg +1 -1
  38. package/package.json +7 -7
  39. package/src/assets/icons/pictogram-internet--dark.svg +15 -0
  40. package/src/assets/icons/pictogram-internet.svg +15 -0
  41. package/src/assets/icons/pictogram-my-orange--dark.svg +6 -0
  42. package/src/assets/icons/pictogram-my-orange.svg +6 -0
  43. package/src/assets/icons/pictogram-tariffs--dark.svg +9 -0
  44. package/src/assets/icons/pictogram-tariffs.svg +9 -0
  45. package/src/components/BodyBanner/styles/mixins.scss +2 -12
  46. package/src/components/Carousel/Carousel.static.ts +182 -67
  47. package/src/components/Carousel/styles/mixins.scss +7 -2
  48. package/src/components/Carousel/tests/Carousel.static.test.jsx +178 -5
  49. package/src/components/Expander/Expander.tsx +4 -0
  50. package/src/components/Expander/styles/style.scss +12 -0
  51. package/src/components/Expander/tests/Expander.conformance.test.jsx +4 -0
  52. package/src/components/Expander/tests/Expander.unit.test.jsx +9 -0
  53. package/src/components/Grid/Grid.tsx +5 -2
  54. package/src/components/Grid/styles/config.scss +3 -2
  55. package/src/components/Grid/tests/Grid.unit.test.jsx +40 -10
  56. package/src/components/Tag/styles/config.scss +5 -1
  57. package/src/components/Tag/styles/mixins.scss +2 -1
  58. package/src/styles/base/globals.scss +1 -0
  59. package/src/styles/export/base.js +1 -1
  60. package/src/styles/tokens/base.scss +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orangesk/orange-design-system",
3
- "version": "2.0.0-beta.43",
3
+ "version": "2.0.0-beta.45",
4
4
  "private": false,
5
5
  "engines": {
6
6
  "node": ">=20.x"
@@ -63,7 +63,7 @@
63
63
  "classnames": "^2.5.1",
64
64
  "daypickr": "^0.3.4",
65
65
  "diff2html": "^3.4.56",
66
- "dompurify": "^3.4.0",
66
+ "dompurify": "^3.4.1",
67
67
  "html-react-parser": "6.0.1",
68
68
  "lorem-ipsum": "^2.0.8",
69
69
  "minisearch": "7.2.0",
@@ -109,10 +109,10 @@
109
109
  "@types/react-dom": "19.2.3",
110
110
  "@types/wnumb": "^1.2.3",
111
111
  "@vitejs/plugin-react": "6.0.1",
112
- "@vitest/browser": "^4.1.4",
113
- "@vitest/browser-playwright": "^4.1.4",
114
- "@vitest/coverage-v8": "^4.1.4",
115
- "@vitest/ui": "^4.1.4",
112
+ "@vitest/browser": "^4.1.5",
113
+ "@vitest/browser-playwright": "^4.1.5",
114
+ "@vitest/coverage-v8": "^4.1.5",
115
+ "@vitest/ui": "^4.1.5",
116
116
  "canvas": "^3.2.3",
117
117
  "fs-extra": "^11.3.4",
118
118
  "glob": "13.0.6",
@@ -130,7 +130,7 @@
130
130
  "sass": "^1.99.0",
131
131
  "svg-sprite": "^2.0.4",
132
132
  "typescript": "6.0.3",
133
- "vitest": "^4.1.4",
133
+ "vitest": "^4.1.5",
134
134
  "vitest-axe": "^0.1.0",
135
135
  "vitest-browser-react": "^2.2.0"
136
136
  },
@@ -0,0 +1,15 @@
1
+ <svg width="61" height="60" viewBox="0 0 61 60" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M55.5 11H6.5C4.29086 11 2.5 12.7909 2.5 15V43C2.5 45.2091 4.29086 47 6.5 47H55.5C57.7091 47 59.5 45.2091 59.5 43V15C59.5 12.7909 57.7091 11 55.5 11Z" fill="#DA8436"/>
3
+ <path d="M15.167 50H45.167" stroke="white" stroke-width="2"/>
4
+ <mask id="mask0_3153_344" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="11" y="11" width="38" height="37">
5
+ <path d="M48.667 11H11.667V48H48.667V11Z" fill="white"/>
6
+ </mask>
7
+ <g mask="url(#mask0_3153_344)">
8
+ <path d="M30.1669 12.3213C20.6801 12.3213 12.9883 20.0131 12.9883 29.4999C12.9883 38.9867 20.6801 46.6785 30.1669 46.6785C39.6537 46.6785 47.3455 38.9867 47.3455 29.4999C47.3455 20.0131 39.6537 12.3213 30.1669 12.3213Z" stroke="white" stroke-width="2" stroke-miterlimit="15.62"/>
9
+ <path d="M30.1668 12.3213C25.3711 12.3213 20.8613 20.0131 20.8613 29.4999C20.8613 38.9867 25.3706 46.6785 30.1668 46.6785C34.9631 46.6785 39.4723 38.9867 39.4723 29.4999C39.4723 20.0131 34.9625 12.3213 30.1668 12.3213Z" stroke="white" stroke-width="2" stroke-miterlimit="15.62"/>
10
+ <path d="M18.7148 18.0469C21.873 20.2891 25.8489 21.6263 30.1673 21.6263C34.4857 21.6263 38.4617 20.2891 41.6199 18.0469" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
11
+ <path d="M41.6199 40.9525C38.4617 38.7103 34.4857 37.373 30.1673 37.373C25.8489 37.373 21.873 38.7103 18.7148 40.9525" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
12
+ <path d="M30.167 12.3213V46.6785" stroke="white" stroke-width="2" stroke-miterlimit="15.62"/>
13
+ <path d="M47.3455 29.5H12.9883" stroke="white" stroke-width="2" stroke-miterlimit="15.62"/>
14
+ </g>
15
+ </svg>
@@ -0,0 +1,15 @@
1
+ <svg width="61" height="60" viewBox="0 0 61 60" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M55.5 11H6.5C4.29086 11 2.5 12.7909 2.5 15V43C2.5 45.2091 4.29086 47 6.5 47H55.5C57.7091 47 59.5 45.2091 59.5 43V15C59.5 12.7909 57.7091 11 55.5 11Z" fill="#FFC48F"/>
3
+ <path d="M15.167 50H45.167" stroke="black" stroke-width="2"/>
4
+ <mask id="mask0_3153_327" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="11" y="11" width="38" height="37">
5
+ <path d="M48.667 11H11.667V48H48.667V11Z" fill="white"/>
6
+ </mask>
7
+ <g mask="url(#mask0_3153_327)">
8
+ <path d="M30.1669 12.3213C20.6801 12.3213 12.9883 20.0131 12.9883 29.4999C12.9883 38.9867 20.6801 46.6785 30.1669 46.6785C39.6537 46.6785 47.3455 38.9867 47.3455 29.4999C47.3455 20.0131 39.6537 12.3213 30.1669 12.3213Z" stroke="black" stroke-width="2" stroke-miterlimit="15.62"/>
9
+ <path d="M30.1668 12.3213C25.3711 12.3213 20.8613 20.0131 20.8613 29.4999C20.8613 38.9867 25.3706 46.6785 30.1668 46.6785C34.9631 46.6785 39.4723 38.9867 39.4723 29.4999C39.4723 20.0131 34.9625 12.3213 30.1668 12.3213Z" stroke="black" stroke-width="2" stroke-miterlimit="15.62"/>
10
+ <path d="M18.7148 18.0469C21.873 20.2891 25.8489 21.6263 30.1673 21.6263C34.4857 21.6263 38.4617 20.2891 41.6199 18.0469" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
11
+ <path d="M41.6199 40.9525C38.4617 38.7103 34.4857 37.373 30.1673 37.373C25.8489 37.373 21.873 38.7103 18.7148 40.9525" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
12
+ <path d="M30.167 12.3213V46.6785" stroke="black" stroke-width="2" stroke-miterlimit="15.62"/>
13
+ <path d="M47.3455 29.5H12.9883" stroke="black" stroke-width="2" stroke-miterlimit="15.62"/>
14
+ </g>
15
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M37.1542 23.745C39.0039 24.7252 40.4724 26.2962 41.3256 28.2078C42.1788 30.1194 42.3677 32.2616 41.8622 34.293C41.3566 36.3244 40.1857 38.1282 38.536 39.4169C36.8864 40.7056 34.8528 41.4051 32.7595 41.4039C30.6661 41.4028 28.6334 40.701 26.9851 39.4105C25.3369 38.12 24.168 36.3149 23.6647 34.283C23.1613 32.251 23.3526 30.109 24.2079 28.1984C25.0632 26.2877 26.5334 24.7183 28.3843 23.7402" stroke="white" stroke-width="1.875"/>
3
+ <path d="M32.7646 19.0078V28.3828" stroke="white" stroke-width="1.875"/>
4
+ <path d="M51.22 40.1969C53.8508 33.8493 58.7873 41.5229 58.7895 32.4C58.7899 23.2763 53.8518 30.9469 51.2237 24.5986C48.5956 18.2503 57.5124 20.1869 51.0625 13.7347C44.6112 7.28175 46.5435 16.1978 40.1977 13.5678C33.85 10.937 41.5232 6.00198 32.4002 6C23.2771 5.99802 30.948 10.9358 24.5993 13.564C18.2507 16.1922 20.1871 7.27691 13.7347 13.7269C7.28103 20.1759 16.1986 18.2441 13.5678 24.5918C10.937 30.9394 6.00047 23.2656 6 32.3894C5.99782 41.5124 10.9359 33.8418 13.5648 40.1883C16.1929 46.537 7.27718 44.6027 13.7268 51.0551C20.1765 57.5074 18.2441 48.5911 24.5918 51.2219C30.9376 53.8519 23.2646 58.7869 32.3892 58.7898C41.5124 58.7917 33.8406 53.8513 40.1891 51.2228C46.5367 48.5967 44.6009 57.5117 51.0547 51.0626C57.5067 44.6127 48.5891 46.5446 51.22 40.1969Z" fill="#DA8436"/>
5
+ <path d="M38.7061 30.6055C39.7286 31.296 40.5907 32.2191 41.2207 33.3116C41.9633 34.5992 42.3559 36.0711 42.3555 37.5723V49.1915H25.2959C24.4933 49.1915 23.7177 48.8636 23.1416 48.2706C22.5648 47.6767 22.2364 46.8659 22.2363 46.0147V37.4786L22.2383 37.3868C22.2697 35.9175 22.6775 34.4845 23.418 33.2325C24.0436 32.1746 24.8878 31.2789 25.8848 30.6055C27.6868 32.1164 29.9483 32.9542 32.2959 32.9542C34.6432 32.9541 36.9042 32.1161 38.7061 30.6055ZM32.2959 16.0723C33.9472 16.0723 35.5367 16.7473 36.7129 17.9581C37.8899 19.1698 38.5557 20.819 38.5557 22.544C38.5556 23.8298 38.1853 25.0845 37.4941 26.1495C36.803 27.2142 35.8234 28.04 34.6826 28.5264C33.5422 29.0127 32.2889 29.1392 31.0801 28.8917C29.8711 28.6441 28.7562 28.033 27.8789 27.1299C27.0014 26.2266 26.4008 25.0721 26.1572 23.8116C25.9137 22.5511 26.0386 21.2445 26.5156 20.0587C26.9927 18.873 27.799 17.8632 28.8281 17.1553C29.857 16.4477 31.064 16.0723 32.2959 16.0723Z" stroke="white" stroke-width="1.88"/>
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M36.6542 23.745C38.5039 24.7252 39.9724 26.2962 40.8256 28.2078C41.6788 30.1194 41.8677 32.2616 41.3622 34.293C40.8566 36.3244 39.6857 38.1282 38.036 39.4169C36.3864 40.7056 34.3528 41.4051 32.2595 41.4039C30.1661 41.4028 28.1334 40.701 26.4851 39.4105C24.8369 38.12 23.668 36.3149 23.1647 34.283C22.6613 32.251 22.8526 30.109 23.7079 28.1984C24.5632 26.2877 26.0334 24.7183 27.8843 23.7402" stroke="black" stroke-width="1.875"/>
3
+ <path d="M32.2646 19.0078V28.3828" stroke="black" stroke-width="1.875"/>
4
+ <path d="M50.72 40.1969C53.3508 33.8493 58.2873 41.5229 58.2895 32.4C58.2899 23.2763 53.3518 30.9469 50.7237 24.5986C48.0956 18.2503 57.0124 20.1869 50.5625 13.7347C44.1112 7.28175 46.0435 16.1978 39.6977 13.5678C33.35 10.937 41.0232 6.00198 31.9002 6C22.7771 5.99802 30.448 10.9358 24.0993 13.564C17.7507 16.1922 19.6871 7.27691 13.2347 13.7269C6.78103 20.1759 15.6986 18.2441 13.0678 24.5918C10.437 30.9394 5.50047 23.2656 5.5 32.3894C5.49782 41.5124 10.4359 33.8418 13.0648 40.1883C15.6929 46.537 6.77718 44.6027 13.2268 51.0551C19.6765 57.5074 17.7441 48.5911 24.0918 51.2219C30.4376 53.8519 22.7646 58.7869 31.8892 58.7898C41.0124 58.7917 33.3406 53.8513 39.6891 51.2228C46.0367 48.5967 44.1009 57.5117 50.5547 51.0626C57.0067 44.6127 48.0891 46.5446 50.72 40.1969Z" fill="#FFC48F"/>
5
+ <path d="M38.2061 30.6055C39.2286 31.296 40.0907 32.2191 40.7207 33.3116C41.4633 34.5992 41.8559 36.0711 41.8555 37.5723V49.1915H24.7959C23.9933 49.1915 23.2177 48.8636 22.6416 48.2706C22.0648 47.6767 21.7364 46.8659 21.7363 46.0147V37.4786L21.7383 37.3868C21.7697 35.9175 22.1775 34.4845 22.918 33.2325C23.5436 32.1746 24.3878 31.2789 25.3848 30.6055C27.1868 32.1164 29.4483 32.9542 31.7959 32.9542C34.1432 32.9541 36.4042 32.1161 38.2061 30.6055ZM31.7959 16.0723C33.4472 16.0723 35.0367 16.7473 36.2129 17.9581C37.3899 19.1698 38.0557 20.819 38.0557 22.544C38.0556 23.8298 37.6853 25.0845 36.9941 26.1495C36.303 27.2142 35.3234 28.04 34.1826 28.5264C33.0422 29.0127 31.7889 29.1392 30.5801 28.8917C29.3711 28.6441 28.2562 28.033 27.3789 27.1299C26.5014 26.2266 25.9008 25.0721 25.6572 23.8116C25.4137 22.5511 25.5386 21.2445 26.0156 20.0587C26.4927 18.873 27.299 17.8632 28.3281 17.1553C29.357 16.4477 30.564 16.0723 31.7959 16.0723Z" stroke="black" stroke-width="1.88"/>
6
+ </svg>
@@ -0,0 +1,9 @@
1
+ <svg width="61" height="60" viewBox="0 0 61 60" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <mask id="mask0_3153_368" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="61" height="60">
3
+ <path d="M60.9375 0H0V60H60.9375V0Z" fill="white"/>
4
+ </mask>
5
+ <g mask="url(#mask0_3153_368)">
6
+ <path d="M45.0009 52.5C45.0009 54.0532 43.7415 55.3123 42.1884 55.3125H18.2812C16.7279 55.3125 15.4688 54.0533 15.4688 52.5V51.0938H45.0009V52.5ZM45.0009 49.6865H15.4688V10.3115H45.0009V49.6865ZM42.1884 4.6875C43.7415 4.68769 45.0009 5.94682 45.0009 7.5V8.90625H15.4688V7.5C15.4688 5.9467 16.7279 4.6875 18.2812 4.6875H42.1884Z" fill="#DA8436"/>
7
+ <path d="M33.5927 33.4381C30.8936 30.7332 28.3136 27.6002 29.5475 26.3652C32.6498 23.2568 32.8566 23.4989 29.7228 19.5941C26.582 15.6857 26.7082 16.3874 22.7752 20.401C20.707 22.6323 22.67 29.7684 29.9612 37.0658C37.2593 44.3632 44.5785 46.2437 46.6187 44.2615C50.8076 40.097 51.1371 40.3321 47.4249 37.3149C43.5234 34.1714 43.7513 34.3959 40.6595 37.4903C39.4257 38.7218 36.2954 36.1361 33.5927 33.4346V33.4381Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
8
+ </g>
9
+ </svg>
@@ -0,0 +1,9 @@
1
+ <svg width="61" height="60" viewBox="0 0 61 60" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <mask id="mask0_3153_361" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="61" height="60">
3
+ <path d="M60.9375 0H0V60H60.9375V0Z" fill="white"/>
4
+ </mask>
5
+ <g mask="url(#mask0_3153_361)">
6
+ <path d="M45.0009 52.5C45.0009 54.0532 43.7415 55.3123 42.1884 55.3125H18.2812C16.7279 55.3125 15.4688 54.0533 15.4688 52.5V51.0938H45.0009V52.5ZM45.0009 49.6865H15.4688V10.3115H45.0009V49.6865ZM42.1884 4.6875C43.7415 4.68769 45.0009 5.94682 45.0009 7.5V8.90625H15.4688V7.5C15.4688 5.9467 16.7279 4.6875 18.2812 4.6875H42.1884Z" fill="#FFC48F"/>
7
+ <path d="M33.5927 33.4381C30.8936 30.7332 28.3136 27.6002 29.5475 26.3652C32.6498 23.2568 32.8566 23.4989 29.7228 19.5941C26.582 15.6857 26.7082 16.3874 22.7752 20.401C20.707 22.6323 22.67 29.7684 29.9612 37.0658C37.2593 44.3632 44.5785 46.2437 46.6187 44.2615C50.8076 40.097 51.1371 40.3321 47.4249 37.3149C43.5234 34.1714 43.7513 34.3959 40.6595 37.4903C39.4257 38.7218 36.2954 36.1361 33.5927 33.4346V33.4381Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
8
+ </g>
9
+ </svg>
@@ -42,7 +42,7 @@
42
42
  width: 100%;
43
43
  display: flex;
44
44
  padding: space.get("large");
45
- gap: convert.to-rem(30px);
45
+ gap: convert.to-rem(60px);
46
46
 
47
47
  > div:not(.body-banner__button) {
48
48
  flex: 1;
@@ -56,6 +56,7 @@
56
56
  @include breakpoint.get("lg", "down") {
57
57
  display: flex;
58
58
  flex-direction: column;
59
+ gap: convert.to-rem(30px);
59
60
  }
60
61
 
61
62
  @include breakpoint.get("sm", "down") {
@@ -82,13 +83,7 @@
82
83
  @mixin button {
83
84
  display: flex;
84
85
  align-items: center;
85
- padding: 0 0 0 space.get("xlarge");
86
86
  margin: 0 !important;
87
-
88
- @include breakpoint.get("lg", "down") {
89
- padding: 0;
90
- margin-top: space.get("small") !important;
91
- }
92
87
  }
93
88
 
94
89
  @mixin large {
@@ -113,9 +108,4 @@
113
108
  display: block;
114
109
  }
115
110
  }
116
-
117
- .body-banner__button {
118
- padding: 0;
119
- margin-top: space.get("small") !important;
120
- }
121
111
  }
@@ -61,6 +61,7 @@ export const defaultConfig: SwiperOptions = {
61
61
  },
62
62
  a11y: {
63
63
  enabled: true,
64
+ scrollOnFocus: false,
64
65
  prevSlideMessage: "Predchádzajúci snímok",
65
66
  nextSlideMessage: "Nasledujúci snímok",
66
67
  paginationBulletMessage: "Prejsť na snímok {index}",
@@ -97,6 +98,76 @@ export default class Carousel {
97
98
  private resizeRafId?: number;
98
99
  private boundWindowResizeHandler: () => void;
99
100
  private bleedResizeHandler?: () => void;
101
+ private static readonly OVERFLOW_EPSILON_PX = 1;
102
+
103
+ private getViewportWrapper(): HTMLElement | null {
104
+ return this.element.querySelector(
105
+ `.${CLASS_VIEWPORT_WRAPPER}`,
106
+ ) as HTMLElement | null;
107
+ }
108
+
109
+ private getSlidesPerView(): number {
110
+ return Number(this.instance?.params?.slidesPerView) || 1;
111
+ }
112
+
113
+ private setScrollbarVisible(visible: boolean): void {
114
+ const scrollbarEl = this.element.querySelector(
115
+ SELECTOR_SCROLLBAR,
116
+ ) as HTMLElement | null;
117
+ if (scrollbarEl) {
118
+ scrollbarEl.style.display = visible ? "" : "none";
119
+ }
120
+ }
121
+
122
+ private getSlidesContentWidth(): number {
123
+ if (!this.instance) {
124
+ return this.track?.scrollWidth || 0;
125
+ }
126
+
127
+ const slides = Array.from(this.instance.slides) as HTMLElement[];
128
+ const widthsSum = slides.reduce((sum, slide) => sum + slide.offsetWidth, 0);
129
+ const spaceBetween = Number(this.instance.params?.spaceBetween) || 0;
130
+ const gaps = Math.max(slides.length - 1, 0) * spaceBetween;
131
+ const measuredWidth = widthsSum + gaps;
132
+
133
+ // Fallback for early lifecycle/test DOM where slides can report 0 width.
134
+ if (widthsSum <= 0 || measuredWidth <= 0) {
135
+ return this.track?.scrollWidth || 0;
136
+ }
137
+
138
+ return measuredWidth;
139
+ }
140
+
141
+ private getOverflowWidth(viewportWrapper?: HTMLElement): number {
142
+ const isBleedRight = this.element.classList.contains(CLASS_BLEED_RIGHT);
143
+ const containerWidth = isBleedRight
144
+ ? this.element.clientWidth || viewportWrapper?.clientWidth || 0
145
+ : this.viewport?.clientWidth || 0;
146
+
147
+ if (containerWidth <= 0) {
148
+ return 0;
149
+ }
150
+
151
+ const contentWidth = this.getSlidesContentWidth();
152
+
153
+ return contentWidth - containerWidth;
154
+ }
155
+
156
+ private hasScrollableContent(viewportWrapper?: HTMLElement): boolean {
157
+ if (!this.instance || !this.instance.params) {
158
+ return false;
159
+ }
160
+
161
+ const overflowWidth = this.getOverflowWidth(viewportWrapper);
162
+ if (overflowWidth !== 0) {
163
+ return overflowWidth > Carousel.OVERFLOW_EPSILON_PX;
164
+ }
165
+
166
+ // Fallback for hidden/zero-width initialization.
167
+ const slidesCount = this.instance.slides.length;
168
+ const slidesPerView = this.getSlidesPerView();
169
+ return slidesCount > slidesPerView;
170
+ }
100
171
 
101
172
  constructor(element: HTMLElement, config?: Partial<SwiperOptions>) {
102
173
  this.element = element;
@@ -131,8 +202,12 @@ export default class Carousel {
131
202
  this.getCustomOptions();
132
203
  }
133
204
 
205
+ const isBleedRight = this.element.classList.contains(CLASS_BLEED_RIGHT);
206
+
134
207
  this.instance = new Swiper(this.viewport, {
135
208
  ...this.config,
209
+ // Swiper watchOverflow can mis-detect with slides offsets; manage bleed-right overflow ourselves.
210
+ watchOverflow: isBleedRight ? false : this.config.watchOverflow,
136
211
  enabled: false,
137
212
  modules: [Navigation, Pagination, Scrollbar, A11y, Keyboard, Mousewheel],
138
213
  on: {
@@ -237,9 +312,7 @@ export default class Carousel {
237
312
  */
238
313
  fixBleedRightScrollbar() {
239
314
  const updateScrollbar = () => {
240
- const viewportWrapper = this.element.querySelector(
241
- `.${CLASS_VIEWPORT_WRAPPER}`,
242
- ) as HTMLElement;
315
+ const viewportWrapper = this.getViewportWrapper();
243
316
  const scrollbar = this.instance?.scrollbar;
244
317
  const swiper = this.instance;
245
318
 
@@ -247,29 +320,35 @@ export default class Carousel {
247
320
  return;
248
321
  }
249
322
 
250
- const minTranslate = swiper.minTranslate();
251
- const maxTranslate = swiper.maxTranslate();
252
- const translateRange = Math.abs(maxTranslate - minTranslate);
323
+ const hasScrollableContent = this.hasScrollableContent(viewportWrapper);
253
324
 
254
- if (translateRange <= 1 || !swiper.enabled) {
255
- if (scrollbar.el) {
256
- scrollbar.el.style.display = "none";
257
- }
325
+ if (!hasScrollableContent) {
326
+ this.setScrollbarVisible(false);
258
327
  return;
259
328
  }
260
329
 
261
- if (scrollbar.el) {
262
- scrollbar.el.style.display = "";
263
- }
330
+ this.setScrollbarVisible(true);
264
331
 
265
332
  const scrollbarWidth = scrollbar.el.offsetWidth;
266
- const viewportWidth = viewportWrapper.clientWidth;
267
- const offsetBefore = Number(swiper.params.slidesOffsetBefore) || 0;
268
- const offsetAfter = Number(swiper.params.slidesOffsetAfter) || 0;
269
- const contentWidth = this.track.scrollWidth + offsetBefore + offsetAfter;
333
+ const viewportWidth =
334
+ this.instance?.width ||
335
+ this.element.clientWidth ||
336
+ viewportWrapper.clientWidth;
337
+ const contentWidth = this.getSlidesContentWidth();
338
+ const minTranslate =
339
+ typeof swiper.minTranslate === "function" ? swiper.minTranslate() : 0;
340
+ const maxTranslate =
341
+ typeof swiper.maxTranslate === "function" ? swiper.maxTranslate() : 0;
342
+ const translateRange = Math.max(Math.abs(maxTranslate - minTranslate), 0);
343
+ const normalizedContentWidth = Math.max(
344
+ contentWidth,
345
+ viewportWidth + translateRange,
346
+ );
270
347
 
271
348
  const visibleRatio =
272
- contentWidth > 0 ? Math.min(viewportWidth / contentWidth, 1) : 1;
349
+ normalizedContentWidth > 0
350
+ ? Math.min(viewportWidth / normalizedContentWidth, 1)
351
+ : 1;
273
352
  const dragSize = visibleRatio * scrollbarWidth;
274
353
  const finalDragSize = Math.max(dragSize, 30);
275
354
 
@@ -348,21 +427,18 @@ export default class Carousel {
348
427
  private updateCarouselEnabledState(): void {
349
428
  if (!this.instance || !this.instance.params) return;
350
429
 
351
- const slidesCount = this.instance.slides.length;
352
- const slidesPerView = Number(this.instance.params.slidesPerView) || 1;
430
+ const viewportWrapper = this.getViewportWrapper();
431
+ const hasScrollableContent = this.hasScrollableContent(
432
+ viewportWrapper || undefined,
433
+ );
353
434
 
354
- if (slidesCount > slidesPerView) {
435
+ if (hasScrollableContent) {
355
436
  this.instance.enable();
356
437
  } else {
357
438
  this.instance.disable();
358
439
  }
359
440
 
360
- const scrollbarEl = this.element.querySelector(
361
- SELECTOR_SCROLLBAR,
362
- ) as HTMLElement | null;
363
- if (scrollbarEl) {
364
- scrollbarEl.style.display = this.instance.enabled ? "" : "none";
365
- }
441
+ this.setScrollbarVisible(this.instance.enabled);
366
442
  }
367
443
 
368
444
  private applyBleedInsets(viewportWrapper: HTMLElement): void {
@@ -370,42 +446,87 @@ export default class Carousel {
370
446
  return;
371
447
  }
372
448
 
449
+ const containerWidth =
450
+ this.element.clientWidth || viewportWrapper.clientWidth || 0;
373
451
  const viewportWidth =
374
- document.documentElement.clientWidth ||
375
- window.visualViewport?.width ||
376
- window.innerWidth;
377
-
378
- const rect = viewportWrapper.getBoundingClientRect();
379
- const insetLeft = Math.max(Math.round(rect.left), 0);
380
- const insetRight = Math.max(Math.round(viewportWidth - rect.right), 0);
381
- const insetAfter = insetRight;
452
+ document.documentElement?.clientWidth || window.innerWidth || 0;
453
+ const wrapperRect = viewportWrapper.getBoundingClientRect();
454
+ const rootRect = this.element.getBoundingClientRect();
455
+ const stableLeftInsetSource =
456
+ rootRect.left > 0 ? rootRect.left : wrapperRect.left;
457
+ const leftInset = Math.max(Math.floor(stableLeftInsetSource), 0);
458
+ const shellWidth = Math.max(Math.floor(viewportWidth), containerWidth, 0);
459
+ const shellMarginLeft = -leftInset;
460
+ const bleedViewportWidth = Math.max(
461
+ shellWidth - leftInset,
462
+ containerWidth,
463
+ 0,
464
+ );
382
465
 
383
- const slidesPerView = Number(this.instance.params.slidesPerView) || 1;
466
+ const projectedContentWidth = this.getSlidesContentWidth();
467
+ const projectedOverflowWidth = projectedContentWidth - containerWidth;
468
+ const slidesPerView = this.getSlidesPerView();
384
469
  const slidesCount = this.instance.slides.length;
385
- const shouldDisableBleed =
386
- viewportWidth >= 2560 || slidesCount <= slidesPerView;
470
+ const hasIntrinsicOverflow =
471
+ projectedContentWidth > 0
472
+ ? projectedOverflowWidth > Carousel.OVERFLOW_EPSILON_PX
473
+ : slidesCount > slidesPerView;
474
+ const shouldDisableBleed = !hasIntrinsicOverflow;
475
+ const shouldEnableBleedClass = !shouldDisableBleed;
476
+ const hadBleedClass = this.element.classList.contains(CLASS_BLEED_RIGHT);
477
+ const nextBleedViewportWidth = shouldDisableBleed
478
+ ? "100%"
479
+ : `${bleedViewportWidth}px`;
480
+ const nextBleedMarginLeft = shouldDisableBleed ? "0px" : `${leftInset}px`;
481
+ const nextBleedShellWidth = shouldDisableBleed ? "100%" : `${shellWidth}px`;
482
+ const nextBleedShellMarginLeft = shouldDisableBleed
483
+ ? "0px"
484
+ : `${shellMarginLeft}px`;
485
+ const geometryChanged =
486
+ hadBleedClass !== shouldEnableBleedClass ||
487
+ this.instance.params.width !==
488
+ (shouldDisableBleed ? undefined : containerWidth) ||
489
+ this.element.style.getPropertyValue("--carousel-bleed-viewport-width") !==
490
+ nextBleedViewportWidth ||
491
+ this.element.style.getPropertyValue("--carousel-bleed-margin-left") !==
492
+ nextBleedMarginLeft ||
493
+ this.element.style.getPropertyValue("--carousel-bleed-shell-width") !==
494
+ nextBleedShellWidth ||
495
+ this.element.style.getPropertyValue(
496
+ "--carousel-bleed-shell-margin-left",
497
+ ) !== nextBleedShellMarginLeft;
498
+
499
+ this.element.classList.toggle(CLASS_BLEED_RIGHT, shouldEnableBleedClass);
500
+
501
+ const baseWidth = shouldDisableBleed ? undefined : containerWidth;
502
+ this.instance.params.width = baseWidth;
503
+ if (this.instance.originalParams) {
504
+ this.instance.originalParams.width = baseWidth;
505
+ }
387
506
 
388
- this.element.classList.toggle(CLASS_BLEED_RIGHT, !shouldDisableBleed);
507
+ this.instance.params.slidesOffsetBefore = 0;
508
+ this.instance.params.slidesOffsetAfter = 0;
509
+ this.element.style.setProperty(
510
+ "--carousel-bleed-viewport-width",
511
+ nextBleedViewportWidth,
512
+ );
513
+ this.element.style.setProperty(
514
+ "--carousel-bleed-margin-left",
515
+ nextBleedMarginLeft,
516
+ );
517
+ this.element.style.setProperty(
518
+ "--carousel-bleed-shell-width",
519
+ nextBleedShellWidth,
520
+ );
521
+ this.element.style.setProperty(
522
+ "--carousel-bleed-shell-margin-left",
523
+ nextBleedShellMarginLeft,
524
+ );
389
525
 
390
- if (shouldDisableBleed) {
391
- this.instance.params.slidesOffsetBefore = 0;
392
- this.instance.params.slidesOffsetAfter = 0;
393
- this.element.style.setProperty("--carousel-bleed-viewport-width", "100%");
394
- this.element.style.setProperty("--carousel-bleed-margin-left", "0px");
395
- } else {
396
- this.instance.params.slidesOffsetBefore = insetLeft;
397
- this.instance.params.slidesOffsetAfter = insetAfter;
398
- this.element.style.setProperty(
399
- "--carousel-bleed-viewport-width",
400
- `${Math.round(viewportWidth)}px`,
401
- );
402
- this.element.style.setProperty(
403
- "--carousel-bleed-margin-left",
404
- `${-insetLeft}px`,
405
- );
526
+ if (geometryChanged) {
527
+ this.instance.update();
406
528
  }
407
-
408
- this.instance.update();
529
+ this.updateCarouselEnabledState();
409
530
  }
410
531
 
411
532
  /**
@@ -418,9 +539,7 @@ export default class Carousel {
418
539
  requestAnimationFrame(() => {
419
540
  if (!this.instance) return;
420
541
 
421
- const viewportWrapper = this.element.querySelector(
422
- `.${CLASS_VIEWPORT_WRAPPER}`,
423
- ) as HTMLElement;
542
+ const viewportWrapper = this.getViewportWrapper();
424
543
  if (!viewportWrapper) return;
425
544
 
426
545
  const updateBleedState = () => {
@@ -587,13 +706,9 @@ export default class Carousel {
587
706
  return;
588
707
  }
589
708
 
590
- const isAtStart = this.instance.isBeginning;
591
- const slidesCount = this.instance.slides.length;
592
- const slidesPerView = this.instance.params.slidesPerView as number;
593
- const activeIndex = this.instance.activeIndex;
594
-
595
- // Check if we've reached the end (when there are no more slides to scroll to)
596
- const isAtEnd = activeIndex + slidesPerView >= slidesCount;
709
+ const isDisabled = !this.instance.enabled;
710
+ const isAtStart = isDisabled || this.instance.isBeginning;
711
+ const isAtEnd = isDisabled || this.instance.isEnd;
597
712
 
598
713
  const prevControls = document.querySelectorAll(
599
714
  `[data-carousel-controls="${this.carouselId}"][data-carousel-action="prev"]`,
@@ -217,7 +217,12 @@
217
217
  overflow: visible;
218
218
 
219
219
  .carousel__viewport-wrapper {
220
- overflow: visible;
220
+ width: var(--carousel-bleed-shell-width, 100%);
221
+ max-width: var(--carousel-bleed-shell-width, 100%);
222
+ margin-left: var(--carousel-bleed-shell-margin-left, 0) !important;
223
+ overflow-x: hidden;
224
+ overflow-x: clip;
225
+ overflow-y: visible;
221
226
  }
222
227
 
223
228
  .carousel__viewport {
@@ -225,6 +230,6 @@
225
230
  max-width: var(--carousel-bleed-viewport-width, 100%);
226
231
  margin-right: 0;
227
232
  margin-left: var(--carousel-bleed-margin-left, 0) !important;
228
- overflow: hidden !important;
233
+ overflow: visible !important;
229
234
  }
230
235
  }