@times-components/ts-components 1.145.1-76ee0965069e2a17bc1f8dcf02d24e8fefd6869a.0 → 1.145.1-7e7a12feaf05c514789e802bf49cadca92e6a2b9.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.
Files changed (143) hide show
  1. package/dist/components/carousel-component/CarouselComponent.stories.js +146 -0
  2. package/dist/components/carousel-component/CarouselItem.d.ts +3 -0
  3. package/dist/components/carousel-component/CarouselItem.js +11 -0
  4. package/dist/components/carousel-component/DefaultNavigationArrow.d.ts +8 -0
  5. package/dist/components/carousel-component/DefaultNavigationArrow.js +6 -0
  6. package/dist/components/carousel-component/DefaultPageDot.d.ts +8 -0
  7. package/dist/components/carousel-component/DefaultPageDot.js +4 -0
  8. package/dist/components/{opta/football/opta-match-stats/matchday-live/__tests__/OptaMatchStatsMatchdayLive.test.d.ts → carousel-component/__tests__/CarouselComponent.test.d.ts} +0 -1
  9. package/dist/components/carousel-component/__tests__/CarouselComponent.test.js +163 -0
  10. package/dist/components/carousel-component/__tests__/CarouselItem.test.d.ts +1 -0
  11. package/dist/components/carousel-component/__tests__/CarouselItem.test.js +80 -0
  12. package/dist/components/carousel-component/__tests__/DefaultNavigationArrow.test.d.ts +1 -0
  13. package/dist/components/carousel-component/__tests__/DefaultNavigationArrow.test.js +62 -0
  14. package/dist/components/carousel-component/__tests__/DefaultPageDot.test.d.ts +1 -0
  15. package/dist/components/carousel-component/__tests__/DefaultPageDot.test.js +68 -0
  16. package/dist/components/carousel-component/hooks/__tests__/useCarousel.test.d.ts +1 -0
  17. package/dist/components/carousel-component/hooks/__tests__/useCarousel.test.js +459 -0
  18. package/dist/components/carousel-component/hooks/useCarousel.d.ts +2 -0
  19. package/dist/components/carousel-component/hooks/useCarousel.js +175 -0
  20. package/dist/components/carousel-component/index.d.ts +4 -0
  21. package/dist/components/carousel-component/index.js +20 -0
  22. package/dist/components/carousel-component/styles.d.ts +27 -0
  23. package/dist/components/carousel-component/styles.js +169 -0
  24. package/dist/components/carousel-component/types.d.ts +53 -0
  25. package/dist/components/carousel-component/types.js +2 -0
  26. package/dist/components/opta/football/opta-match-stats/shared/styles.js +1 -8
  27. package/dist/components/trip-cards/SkeletonCard.d.ts +6 -0
  28. package/dist/components/trip-cards/SkeletonCard.js +21 -0
  29. package/dist/components/trip-cards/TripCard.d.ts +3 -0
  30. package/dist/components/trip-cards/TripCard.js +49 -0
  31. package/dist/components/trip-cards/TripCards.stories.d.ts +1 -0
  32. package/dist/components/trip-cards/TripCards.stories.js +189 -0
  33. package/dist/components/trip-cards/TripCardsLayout.d.ts +3 -0
  34. package/dist/components/trip-cards/TripCardsLayout.js +37 -0
  35. package/dist/components/trip-cards/__tests__/SkeletonCard.test.d.ts +1 -0
  36. package/dist/components/trip-cards/__tests__/SkeletonCard.test.js +139 -0
  37. package/dist/components/trip-cards/__tests__/TripCard.test.d.ts +1 -0
  38. package/dist/components/trip-cards/__tests__/TripCard.test.js +95 -0
  39. package/dist/components/trip-cards/__tests__/TripCardsLayout.test.d.ts +1 -0
  40. package/dist/components/trip-cards/__tests__/TripCardsLayout.test.js +277 -0
  41. package/dist/components/trip-cards/__tests__/assets.test.d.ts +1 -0
  42. package/dist/components/trip-cards/__tests__/assets.test.js +165 -0
  43. package/dist/components/trip-cards/__tests__/helpers.test.d.ts +1 -0
  44. package/dist/components/trip-cards/__tests__/helpers.test.js +216 -0
  45. package/dist/components/trip-cards/__tests__/index.test.d.ts +1 -0
  46. package/dist/components/trip-cards/__tests__/index.test.js +433 -0
  47. package/dist/components/trip-cards/__tests__/mockData.test.d.ts +1 -0
  48. package/dist/components/trip-cards/__tests__/mockData.test.js +57 -0
  49. package/dist/components/trip-cards/__tests__/skeletonStyles.test.d.ts +1 -0
  50. package/dist/components/trip-cards/__tests__/skeletonStyles.test.js +194 -0
  51. package/dist/components/trip-cards/assets/BoatIcon.d.ts +1 -0
  52. package/dist/components/trip-cards/assets/BoatIcon.js +4 -0
  53. package/dist/components/trip-cards/assets/CalendarIcon.d.ts +1 -0
  54. package/dist/components/trip-cards/assets/CalendarIcon.js +4 -0
  55. package/dist/components/trip-cards/assets/ChevronRightIcon.d.ts +1 -0
  56. package/dist/components/trip-cards/assets/ChevronRightIcon.js +4 -0
  57. package/dist/components/trip-cards/assets/LocationIcon.d.ts +1 -0
  58. package/dist/components/trip-cards/assets/LocationIcon.js +4 -0
  59. package/dist/components/trip-cards/assets/MoonIcon.d.ts +1 -0
  60. package/dist/components/trip-cards/assets/MoonIcon.js +4 -0
  61. package/dist/components/trip-cards/assets/index.d.ts +6 -0
  62. package/dist/components/trip-cards/assets/index.js +7 -0
  63. package/dist/components/trip-cards/helpers.d.ts +4 -0
  64. package/dist/components/trip-cards/helpers.js +115 -0
  65. package/dist/components/trip-cards/index.d.ts +4 -0
  66. package/dist/components/trip-cards/index.js +70 -0
  67. package/dist/components/trip-cards/mockData.d.ts +3 -0
  68. package/dist/components/trip-cards/mockData.js +317 -0
  69. package/dist/components/trip-cards/skeletonStyles.d.ts +9 -0
  70. package/dist/components/trip-cards/skeletonStyles.js +37 -0
  71. package/dist/components/trip-cards/styles.d.ts +38 -0
  72. package/dist/components/trip-cards/styles.js +401 -0
  73. package/dist/components/trip-cards/types.d.ts +119 -0
  74. package/dist/components/trip-cards/types.js +2 -0
  75. package/dist/index.d.ts +1 -0
  76. package/dist/index.js +2 -4
  77. package/package.json +3 -3
  78. package/rnw.js +1 -1
  79. package/src/components/carousel-component/CarouselComponent.stories.tsx +220 -0
  80. package/src/components/carousel-component/CarouselItem.tsx +25 -0
  81. package/src/components/carousel-component/DefaultNavigationArrow.tsx +37 -0
  82. package/src/components/carousel-component/DefaultPageDot.tsx +20 -0
  83. package/src/components/carousel-component/__tests__/CarouselComponent.test.tsx +259 -0
  84. package/src/components/carousel-component/__tests__/CarouselItem.test.tsx +140 -0
  85. package/src/components/carousel-component/__tests__/DefaultNavigationArrow.test.tsx +153 -0
  86. package/src/components/carousel-component/__tests__/DefaultPageDot.test.tsx +105 -0
  87. package/src/components/carousel-component/hooks/__tests__/useCarousel.test.ts +625 -0
  88. package/src/components/carousel-component/hooks/useCarousel.ts +231 -0
  89. package/src/components/carousel-component/index.tsx +92 -0
  90. package/src/components/carousel-component/styles.ts +185 -0
  91. package/src/components/carousel-component/types.ts +62 -0
  92. package/src/components/opta/football/opta-match-stats/commentary/__tests__/__snapshots__/OptaMatchStatsCommentary.test.tsx.snap +1 -1
  93. package/src/components/opta/football/opta-match-stats/shared/styles.ts +0 -8
  94. package/src/components/opta/football/opta-match-stats/stats-graphs/__tests__/__snapshots__/OptaMatchStatsGraphs.test.tsx.snap +1 -1
  95. package/src/components/trip-cards/SkeletonCard.tsx +62 -0
  96. package/src/components/trip-cards/TripCard.tsx +143 -0
  97. package/src/components/trip-cards/TripCards.stories.tsx +254 -0
  98. package/src/components/trip-cards/TripCardsLayout.tsx +108 -0
  99. package/src/components/trip-cards/__tests__/SkeletonCard.test.tsx +169 -0
  100. package/src/components/trip-cards/__tests__/TripCard.test.tsx +120 -0
  101. package/src/components/trip-cards/__tests__/TripCardsLayout.test.tsx +532 -0
  102. package/src/components/trip-cards/__tests__/assets.test.tsx +206 -0
  103. package/src/components/trip-cards/__tests__/helpers.test.ts +266 -0
  104. package/src/components/trip-cards/__tests__/index.test.tsx +495 -0
  105. package/src/components/trip-cards/__tests__/mockData.test.ts +67 -0
  106. package/src/components/trip-cards/__tests__/skeletonStyles.test.tsx +256 -0
  107. package/src/components/trip-cards/assets/BoatIcon.tsx +17 -0
  108. package/src/components/trip-cards/assets/CalendarIcon.tsx +17 -0
  109. package/src/components/trip-cards/assets/ChevronRightIcon.tsx +20 -0
  110. package/src/components/trip-cards/assets/LocationIcon.tsx +17 -0
  111. package/src/components/trip-cards/assets/MoonIcon.tsx +17 -0
  112. package/src/components/trip-cards/assets/index.ts +7 -0
  113. package/src/components/trip-cards/helpers.ts +150 -0
  114. package/src/components/trip-cards/index.tsx +119 -0
  115. package/src/components/trip-cards/mockData.ts +345 -0
  116. package/src/components/trip-cards/skeletonStyles.ts +46 -0
  117. package/src/components/trip-cards/styles.ts +446 -0
  118. package/src/components/trip-cards/types.ts +128 -0
  119. package/src/index.ts +2 -3
  120. package/dist/components/opta/football/opta-match-stats/matchday-live/DesktopWidget.d.ts +0 -10
  121. package/dist/components/opta/football/opta-match-stats/matchday-live/DesktopWidget.js +0 -69
  122. package/dist/components/opta/football/opta-match-stats/matchday-live/MobileWidget.d.ts +0 -12
  123. package/dist/components/opta/football/opta-match-stats/matchday-live/MobileWidget.js +0 -90
  124. package/dist/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.d.ts +0 -12
  125. package/dist/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.js +0 -10
  126. package/dist/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.stories.js +0 -24
  127. package/dist/components/opta/football/opta-match-stats/matchday-live/__tests__/OptaMatchStatsMatchdayLive.test.js +0 -48
  128. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/MatchdayLiveController.d.ts +0 -1
  129. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/MatchdayLiveController.js +0 -19
  130. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/NavigationWrapper.d.ts +0 -12
  131. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/NavigationWrapper.js +0 -67
  132. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/WidgetContainer.d.ts +0 -6
  133. package/dist/components/opta/football/opta-match-stats/matchday-live/styles/WidgetContainer.js +0 -714
  134. package/src/components/opta/football/opta-match-stats/matchday-live/DesktopWidget.tsx +0 -108
  135. package/src/components/opta/football/opta-match-stats/matchday-live/MobileWidget.tsx +0 -158
  136. package/src/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.stories.tsx +0 -38
  137. package/src/components/opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.tsx +0 -23
  138. package/src/components/opta/football/opta-match-stats/matchday-live/__tests__/OptaMatchStatsMatchdayLive.test.tsx +0 -61
  139. package/src/components/opta/football/opta-match-stats/matchday-live/__tests__/__snapshots__/OptaMatchStatsMatchdayLive.test.tsx.snap +0 -61
  140. package/src/components/opta/football/opta-match-stats/matchday-live/styles/MatchdayLiveController.tsx +0 -19
  141. package/src/components/opta/football/opta-match-stats/matchday-live/styles/NavigationWrapper.tsx +0 -81
  142. package/src/components/opta/football/opta-match-stats/matchday-live/styles/WidgetContainer.tsx +0 -745
  143. /package/dist/components/{opta/football/opta-match-stats/matchday-live/OptaMatchStatsMatchdayLive.stories.d.ts → carousel-component/CarouselComponent.stories.d.ts} +0 -0
@@ -0,0 +1,231 @@
1
+ import { useState, useEffect, useRef, useCallback } from 'react';
2
+ import { UseCarouselOptions, UseCarouselReturn } from '../types';
3
+
4
+ export const useCarousel = (
5
+ totalItems: number,
6
+ options: UseCarouselOptions = {}
7
+ ): UseCarouselReturn => {
8
+ const { itemsPerPage = 2, onPageChange } = options;
9
+
10
+ const [currentPage, setCurrentPage] = useState(0);
11
+ const carouselRef = useRef<HTMLDivElement>(null);
12
+ const isScrollingRef = useRef(false);
13
+ const isDraggingRef = useRef(false);
14
+ const startXRef = useRef(0);
15
+ const touchStartXRef = useRef<number | null>(null);
16
+ const isSwipingRef = useRef(false);
17
+
18
+ const totalPages = Math.ceil(totalItems / itemsPerPage);
19
+
20
+ const scrollToPage = useCallback(
21
+ (page: number) => {
22
+ if (carouselRef.current) {
23
+ const cardElements = carouselRef.current.children;
24
+
25
+ if (cardElements.length > 0) {
26
+ isScrollingRef.current = true;
27
+
28
+ const container = carouselRef.current;
29
+ const targetCardIndex = page * itemsPerPage;
30
+ const targetCard = cardElements[targetCardIndex] as HTMLElement;
31
+
32
+ if (targetCard) {
33
+ const targetScroll = targetCard.offsetLeft;
34
+
35
+ container.scrollTo({
36
+ left: targetScroll,
37
+ behavior: 'smooth'
38
+ });
39
+ setCurrentPage(page);
40
+
41
+ if (onPageChange) {
42
+ onPageChange(page);
43
+ }
44
+
45
+ setTimeout(() => {
46
+ isScrollingRef.current = false;
47
+ }, 400);
48
+ }
49
+ }
50
+ }
51
+ },
52
+ [itemsPerPage, onPageChange]
53
+ );
54
+
55
+ const handlePrevious = useCallback(
56
+ () => {
57
+ const newPage = Math.max(0, currentPage - 1);
58
+ scrollToPage(newPage);
59
+ },
60
+ [currentPage, scrollToPage]
61
+ );
62
+
63
+ const handleNext = useCallback(
64
+ () => {
65
+ const newPage = Math.min(totalPages - 1, currentPage + 1);
66
+ scrollToPage(newPage);
67
+ },
68
+ [currentPage, totalPages, scrollToPage]
69
+ );
70
+
71
+ const handleMouseDown = useCallback((e: React.MouseEvent) => {
72
+ if (!carouselRef.current) {
73
+ return;
74
+ }
75
+ e.preventDefault();
76
+ isDraggingRef.current = true;
77
+ startXRef.current = e.pageX;
78
+ carouselRef.current.style.cursor = 'grabbing';
79
+ }, []);
80
+
81
+ const handleMouseUp = useCallback(
82
+ (e: React.MouseEvent) => {
83
+ if (!isDraggingRef.current) {
84
+ return;
85
+ }
86
+ isDraggingRef.current = false;
87
+
88
+ if (carouselRef.current) {
89
+ carouselRef.current.style.cursor = 'grab';
90
+
91
+ const endX = e.pageX;
92
+ const diff = startXRef.current - endX;
93
+
94
+ if (Math.abs(diff) > 30) {
95
+ if (diff > 0) {
96
+ handleNext();
97
+ } else {
98
+ handlePrevious();
99
+ }
100
+ }
101
+ }
102
+ },
103
+ [handleNext, handlePrevious]
104
+ );
105
+
106
+ const handleMouseLeave = useCallback(
107
+ (e: React.MouseEvent) => {
108
+ if (!isDraggingRef.current) {
109
+ return;
110
+ }
111
+ isDraggingRef.current = false;
112
+
113
+ if (carouselRef.current) {
114
+ carouselRef.current.style.cursor = 'grab';
115
+
116
+ const endX = e.pageX;
117
+ const diff = startXRef.current - endX;
118
+
119
+ if (Math.abs(diff) > 30) {
120
+ if (diff > 0) {
121
+ handleNext();
122
+ } else {
123
+ handlePrevious();
124
+ }
125
+ }
126
+ }
127
+ },
128
+ [handleNext, handlePrevious]
129
+ );
130
+
131
+ const handleTouchStart = (e: React.TouchEvent) => {
132
+ if (!carouselRef.current) {
133
+ return;
134
+ }
135
+ touchStartXRef.current = e.touches[0].clientX;
136
+ isSwipingRef.current = false;
137
+ };
138
+
139
+ const handleTouchMove = (e: React.TouchEvent) => {
140
+ if (touchStartXRef.current === null || isSwipingRef.current) {
141
+ return;
142
+ }
143
+
144
+ const currentX = e.touches[0].clientX;
145
+ const diff = touchStartXRef.current - currentX;
146
+
147
+ if (Math.abs(diff) > 30) {
148
+ isSwipingRef.current = true;
149
+
150
+ if (diff > 0) {
151
+ handleNext();
152
+ } else {
153
+ handlePrevious();
154
+ }
155
+ }
156
+ };
157
+
158
+ const handleTouchEnd = () => {
159
+ touchStartXRef.current = null;
160
+ isSwipingRef.current = false;
161
+ };
162
+
163
+ const handleScroll = useCallback(
164
+ () => {
165
+ if (isScrollingRef.current) {
166
+ return;
167
+ }
168
+
169
+ if (carouselRef.current) {
170
+ const container = carouselRef.current;
171
+ const children = container.children;
172
+ if (children.length === 0) {
173
+ return;
174
+ }
175
+
176
+ const scrollLeft = container.scrollLeft;
177
+
178
+ let closestPage = 0;
179
+ let closestDistance = Infinity;
180
+
181
+ for (let page = 0; page < totalPages; page++) {
182
+ const cardIndex = page * itemsPerPage;
183
+ if (cardIndex < children.length) {
184
+ const card = children[cardIndex] as HTMLElement;
185
+ const distance = Math.abs(card.offsetLeft - scrollLeft);
186
+ if (distance < closestDistance) {
187
+ closestDistance = distance;
188
+ closestPage = page;
189
+ }
190
+ }
191
+ }
192
+
193
+ if (closestPage !== currentPage) {
194
+ setCurrentPage(closestPage);
195
+ if (onPageChange) {
196
+ onPageChange(closestPage);
197
+ }
198
+ }
199
+ }
200
+ },
201
+ [totalPages, itemsPerPage, onPageChange]
202
+ );
203
+
204
+ useEffect(
205
+ () => {
206
+ const carousel = carouselRef.current;
207
+ if (carousel) {
208
+ carousel.addEventListener('scroll', handleScroll);
209
+ return () => carousel.removeEventListener('scroll', handleScroll);
210
+ }
211
+ return undefined;
212
+ },
213
+ [handleScroll]
214
+ );
215
+
216
+ return {
217
+ currentPage,
218
+ totalPages,
219
+ carouselRef,
220
+ isScrolling: isScrollingRef.current,
221
+ handlePrevious,
222
+ handleNext,
223
+ scrollToPage,
224
+ handleMouseDown,
225
+ handleMouseUp,
226
+ handleMouseLeave,
227
+ handleTouchStart,
228
+ handleTouchMove,
229
+ handleTouchEnd
230
+ };
231
+ };
@@ -0,0 +1,92 @@
1
+ import React from 'react';
2
+ import { useCarousel } from './hooks/useCarousel';
3
+ import {
4
+ CarouselContainer,
5
+ CarouselWrapper,
6
+ CarouselContent,
7
+ CardsRow,
8
+ PageControl
9
+ } from './styles';
10
+ import { DefaultNavigationArrow } from './DefaultNavigationArrow';
11
+ import { DefaultPageDot } from './DefaultPageDot';
12
+ import { CarouselComponentProps } from './types';
13
+
14
+ export const CarouselComponent: React.FC<CarouselComponentProps> = ({
15
+ items,
16
+ options,
17
+ showArrows = true,
18
+ showDots = true,
19
+ arrowComponent: CustomArrow,
20
+ dotComponent: CustomDot,
21
+ className
22
+ }) => {
23
+ const {
24
+ currentPage,
25
+ totalPages,
26
+ carouselRef,
27
+ handlePrevious,
28
+ handleNext,
29
+ scrollToPage,
30
+ handleMouseDown,
31
+ handleMouseUp,
32
+ handleMouseLeave,
33
+ handleTouchStart,
34
+ handleTouchMove,
35
+ handleTouchEnd
36
+ } = useCarousel(items.length, options);
37
+
38
+ const ArrowComponent = CustomArrow || DefaultNavigationArrow;
39
+ const DotComponent = CustomDot || DefaultPageDot;
40
+
41
+ return (
42
+ <CarouselContainer className={className}>
43
+ <CarouselWrapper>
44
+ {showArrows && (
45
+ <ArrowComponent
46
+ direction="left"
47
+ onClick={handlePrevious}
48
+ disabled={currentPage === 0}
49
+ />
50
+ )}
51
+
52
+ <CarouselContent>
53
+ <CardsRow
54
+ ref={carouselRef}
55
+ onMouseDown={handleMouseDown}
56
+ onMouseUp={handleMouseUp}
57
+ onMouseLeave={handleMouseLeave}
58
+ onTouchStart={handleTouchStart}
59
+ onTouchMove={handleTouchMove}
60
+ onTouchEnd={handleTouchEnd}
61
+ >
62
+ {items}
63
+ </CardsRow>
64
+ </CarouselContent>
65
+
66
+ {showArrows && (
67
+ <ArrowComponent
68
+ direction="right"
69
+ onClick={handleNext}
70
+ disabled={currentPage >= totalPages - 1}
71
+ />
72
+ )}
73
+ </CarouselWrapper>
74
+
75
+ {showDots &&
76
+ totalPages > 1 && (
77
+ <PageControl>
78
+ {Array.from({ length: totalPages }).map((_, pageIndex) => (
79
+ <DotComponent
80
+ key={pageIndex}
81
+ active={pageIndex === currentPage}
82
+ onClick={() => scrollToPage(pageIndex)}
83
+ index={pageIndex}
84
+ />
85
+ ))}
86
+ </PageControl>
87
+ )}
88
+ </CarouselContainer>
89
+ );
90
+ };
91
+
92
+ export { CarouselItem } from './CarouselItem';
@@ -0,0 +1,185 @@
1
+ import styled, { css } from 'styled-components';
2
+ import { ResponsiveConfig } from './types';
3
+ export const breakpoints = {
4
+ sm: '390px',
5
+ md: '768px',
6
+ lg: '1024px',
7
+ xl: '1320px'
8
+ };
9
+
10
+ export const colors = {
11
+ primary: '#005C8A',
12
+ white: '#FFFFFF'
13
+ };
14
+
15
+ export const ItemContainer = styled.div<{
16
+ widthItemConfig?: ResponsiveConfig;
17
+ maxWidthItemConfig?: ResponsiveConfig;
18
+ }>`
19
+ scroll-snap-align: start;
20
+ display: flex;
21
+ flex-direction: column;
22
+ align-self: stretch;
23
+
24
+ ${props => {
25
+ if (!props.widthItemConfig) {
26
+ return '';
27
+ }
28
+ const { mobile, tablet, desktop, xl } = props.widthItemConfig;
29
+ return css`
30
+ ${mobile &&
31
+ `
32
+ @media (min-width: ${breakpoints.sm}) {
33
+ flex: 0 0 ${mobile};
34
+ }
35
+ `}
36
+ ${tablet &&
37
+ `
38
+ @media (min-width: ${breakpoints.md}) {
39
+ flex: 0 0 ${tablet};
40
+ }
41
+ `}
42
+ ${desktop &&
43
+ `
44
+ @media (min-width: ${breakpoints.lg}) {
45
+ flex: 0 0 ${desktop};
46
+ }
47
+ `}
48
+ ${xl &&
49
+ `
50
+ @media (min-width: ${breakpoints.xl}) {
51
+ flex: 0 0 ${xl};
52
+ }
53
+ `}
54
+ `;
55
+ }} ${props => {
56
+ if (!props.maxWidthItemConfig) {
57
+ return '';
58
+ }
59
+ const { mobile, tablet, desktop, xl } = props.maxWidthItemConfig;
60
+ return css`
61
+ ${mobile &&
62
+ `
63
+ @media (min-width: ${breakpoints.sm}) {
64
+ max-width: ${mobile};
65
+ }
66
+ `}
67
+ ${tablet &&
68
+ `
69
+ @media (min-width: ${breakpoints.md}) {
70
+ max-width: ${tablet};
71
+ }
72
+ `}
73
+ ${desktop &&
74
+ `
75
+ @media (min-width: ${breakpoints.lg}) {
76
+ max-width: ${desktop};
77
+ }
78
+ `}
79
+ ${xl &&
80
+ `
81
+ @media (min-width: ${breakpoints.xl}) {
82
+ max-width: ${xl};
83
+ }
84
+ `}
85
+ `;
86
+ }};
87
+ `;
88
+
89
+ export const CarouselContainer = styled.div`
90
+ width: 100%;
91
+ `;
92
+
93
+ export const CarouselWrapper = styled.div`
94
+ position: relative;
95
+ width: 100%;
96
+ `;
97
+
98
+ export const CarouselContent = styled.div`
99
+ overflow: hidden;
100
+ `;
101
+
102
+ export const CardsRow = styled.div`
103
+ display: flex;
104
+ gap: 20px;
105
+ overflow-x: hidden;
106
+ scroll-snap-type: x mandatory;
107
+ scrollbar-width: none;
108
+ -ms-overflow-style: none;
109
+ padding: 0;
110
+ scroll-behavior: smooth;
111
+ cursor: grab;
112
+ user-select: none;
113
+ align-items: stretch;
114
+
115
+ &::-webkit-scrollbar {
116
+ display: none;
117
+ }
118
+
119
+ &:active {
120
+ cursor: grabbing;
121
+ }
122
+ `;
123
+
124
+ export const PageControl = styled.div`
125
+ display: flex;
126
+ justify-content: center;
127
+ align-items: center;
128
+ gap: 10px;
129
+ padding: 12px;
130
+ background: ${colors.white};
131
+ `;
132
+
133
+ export const NavigationArrowButton = styled.button<{
134
+ direction: 'left' | 'right';
135
+ disabled?: boolean;
136
+ }>`
137
+ display: none;
138
+ position: absolute;
139
+ top: 50%;
140
+ transform: translateY(-50%);
141
+ ${({ direction }) =>
142
+ direction === 'left' ? 'left: -68px;' : 'right: -68px;'} z-index: 10;
143
+ width: 48px;
144
+ height: 48px;
145
+ border: none;
146
+ border-radius: 50%;
147
+ background: ${({ disabled }) => (disabled ? '#CCCCCC' : colors.primary)};
148
+ cursor: ${({ disabled }) => (disabled ? 'default' : 'pointer')};
149
+ align-items: center;
150
+ justify-content: center;
151
+ transition: background 0.2s ease;
152
+ pointer-events: ${({ disabled }) => (disabled ? 'none' : 'auto')};
153
+
154
+ svg {
155
+ width: 24px;
156
+ height: 24px;
157
+ }
158
+
159
+ svg path {
160
+ stroke: ${colors.white};
161
+ }
162
+
163
+ &:hover:not(:disabled) {
164
+ background: #004a6e;
165
+ }
166
+
167
+ @media (min-width: ${breakpoints.lg}) {
168
+ display: flex;
169
+ }
170
+ `;
171
+
172
+ export const PageDotButton = styled.button<{ active: boolean }>`
173
+ width: 8px;
174
+ height: 8px;
175
+ border-radius: 1000px;
176
+ border: none;
177
+ padding: 0;
178
+ background: ${({ active }) => (active ? '#01000D' : '#AAAAAA')};
179
+ cursor: pointer;
180
+ transition: background 0.2s ease;
181
+
182
+ &:hover {
183
+ background: #01000d;
184
+ }
185
+ `;
@@ -0,0 +1,62 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ export interface ResponsiveConfig {
4
+ xs?: string;
5
+ mobile?: string;
6
+ tablet?: string;
7
+ desktop?: string;
8
+ xl?: string;
9
+ }
10
+
11
+ export type ResponsiveConfigNoXs = Omit<ResponsiveConfig, 'xs'>;
12
+
13
+ export interface ArrowComponentProps {
14
+ direction: 'left' | 'right';
15
+ onClick: () => void;
16
+ disabled: boolean;
17
+ }
18
+
19
+ export interface DotComponentProps {
20
+ active: boolean;
21
+ onClick: () => void;
22
+ index: number;
23
+ }
24
+
25
+ export interface CarouselComponentProps {
26
+ items: ReactNode[];
27
+ options?: UseCarouselOptions;
28
+ showArrows?: boolean;
29
+ showDots?: boolean;
30
+ arrowComponent?: React.ComponentType<ArrowComponentProps>;
31
+ dotComponent?: React.ComponentType<DotComponentProps>;
32
+ className?: string;
33
+ }
34
+
35
+ export interface CarouselItemProps {
36
+ children: ReactNode;
37
+ widthItemConfig?: ResponsiveConfig;
38
+ maxWidthItemConfig?: ResponsiveConfigNoXs;
39
+ className?: string;
40
+ }
41
+
42
+ // Carousel Hook Types
43
+ export interface UseCarouselOptions {
44
+ itemsPerPage?: number;
45
+ onPageChange?: (page: number) => void;
46
+ }
47
+
48
+ export interface UseCarouselReturn {
49
+ currentPage: number;
50
+ totalPages: number;
51
+ carouselRef: React.RefObject<HTMLDivElement>;
52
+ isScrolling: boolean;
53
+ handlePrevious: () => void;
54
+ handleNext: () => void;
55
+ scrollToPage: (page: number) => void;
56
+ handleMouseDown: (e: React.MouseEvent) => void;
57
+ handleMouseUp: (e: React.MouseEvent) => void;
58
+ handleMouseLeave: (e: React.MouseEvent<Element, MouseEvent>) => void;
59
+ handleTouchStart: (e: React.TouchEvent) => void;
60
+ handleTouchMove: (e: React.TouchEvent) => void;
61
+ handleTouchEnd: () => void;
62
+ }
@@ -3,7 +3,7 @@
3
3
  exports[`OptaMatchStatsCommentary renders and initialises widget 1`] = `
4
4
  <DocumentFragment>
5
5
  <div
6
- class="sc-bxivhb eKHCQT"
6
+ class="sc-bxivhb hlADP"
7
7
  >
8
8
  <h3>
9
9
  Commentary
@@ -54,13 +54,5 @@ export const WidgetWrapper = styled.div<{
54
54
  @media (max-width: ${maxMDBreakpoint}px) {
55
55
  display: none;
56
56
  }
57
-
58
- ${props =>
59
- props.isApp &&
60
- `
61
- @media(prefers-color-scheme: dark) {
62
- color: ${darkTextColor} !important;
63
- }
64
- `}
65
57
  }
66
58
  `;
@@ -3,7 +3,7 @@
3
3
  exports[`OptaMatchStatsSummary should render correctly 1`] = `
4
4
  <DocumentFragment>
5
5
  <div
6
- class="sc-bxivhb dwwqvg"
6
+ class="sc-bxivhb JyPwY"
7
7
  >
8
8
  <h3>
9
9
  Match Stats
@@ -0,0 +1,62 @@
1
+ import React, { FC } from 'react';
2
+ import { Placeholder } from '@times-components/image';
3
+ import {
4
+ CardContainer,
5
+ ImageContainer,
6
+ CardContent,
7
+ TopContainer,
8
+ BottomContainer,
9
+ DataPointsList,
10
+ DataPoint,
11
+ PriceSection,
12
+ PriceContainer
13
+ } from './styles';
14
+ import {
15
+ SkeletonLine,
16
+ SkeletonHeadline,
17
+ SkeletonPrice,
18
+ SkeletonButton
19
+ } from './skeletonStyles';
20
+ import { ImageHeightConfig } from './types';
21
+
22
+ export const SkeletonCard: FC<{
23
+ isStaticGrid?: boolean;
24
+ imgHeight?: Omit<ImageHeightConfig, '$heightXs'>;
25
+ }> = ({ isStaticGrid, imgHeight = {} }) => {
26
+ return (
27
+ <CardContainer data-testid="skeleton-card-container">
28
+ <ImageContainer
29
+ data-testid="skeleton-image-container"
30
+ isStaticGrid={isStaticGrid}
31
+ {...imgHeight}
32
+ >
33
+ <Placeholder />
34
+ </ImageContainer>
35
+ <CardContent data-testid="skeleton-card-content">
36
+ <TopContainer data-testid="skeleton-top-container">
37
+ <SkeletonHeadline data-testid="skeleton-headline" />
38
+ <DataPointsList data-testid="skeleton-data-points-list">
39
+ {[1, 2, 3, 4].map(i => (
40
+ <DataPoint key={i} data-testid={`skeleton-data-point-${i}`}>
41
+ <SkeletonLine width="80px" data-testid={`skeleton-line-${i}`} />
42
+ </DataPoint>
43
+ ))}
44
+ </DataPointsList>
45
+ </TopContainer>
46
+ <BottomContainer data-testid="skeleton-bottom-container">
47
+ <PriceSection data-testid="skeleton-price-section">
48
+ <PriceContainer data-testid="skeleton-price-container">
49
+ <SkeletonLine
50
+ width="40px"
51
+ marginBottom="4px"
52
+ data-testid="skeleton-price-label"
53
+ />
54
+ <SkeletonPrice data-testid="skeleton-price" />
55
+ </PriceContainer>
56
+ </PriceSection>
57
+ <SkeletonButton as="div" data-testid="skeleton-button" />
58
+ </BottomContainer>
59
+ </CardContent>
60
+ </CardContainer>
61
+ );
62
+ };