@telus-uds/components-base 3.26.0 → 3.28.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +35 -2
  2. package/lib/cjs/Card/Card.js +34 -13
  3. package/lib/cjs/Card/CardBase.js +90 -14
  4. package/lib/cjs/Card/PressableCardBase.js +147 -8
  5. package/lib/cjs/Carousel/Carousel.js +105 -50
  6. package/lib/cjs/Carousel/CarouselContext.js +10 -4
  7. package/lib/cjs/Carousel/CarouselItem/CarouselItem.js +11 -7
  8. package/lib/cjs/Carousel/Constants.js +11 -2
  9. package/lib/cjs/Checkbox/Checkbox.js +43 -13
  10. package/lib/cjs/ExpandCollapse/Control.js +5 -1
  11. package/lib/cjs/ExpandCollapse/ExpandCollapse.js +17 -8
  12. package/lib/cjs/ExpandCollapse/Panel.js +7 -2
  13. package/lib/cjs/IconButton/IconButton.js +10 -5
  14. package/lib/cjs/List/List.js +24 -9
  15. package/lib/cjs/List/ListItem.js +18 -1
  16. package/lib/cjs/List/ListItemBase.js +27 -8
  17. package/lib/cjs/List/ListItemMark.js +33 -62
  18. package/lib/cjs/List/PressableListItemBase.js +1 -0
  19. package/lib/cjs/Modal/Modal.js +21 -11
  20. package/lib/cjs/Progress/Progress.js +19 -5
  21. package/lib/cjs/Progress/ProgressBar.js +22 -4
  22. package/lib/cjs/Progress/ProgressContext.js +11 -0
  23. package/lib/cjs/SideNav/Item.js +3 -3
  24. package/lib/cjs/SideNav/ItemsGroup.js +46 -19
  25. package/lib/cjs/SideNav/SideNav.js +29 -13
  26. package/lib/esm/Card/Card.js +34 -13
  27. package/lib/esm/Card/CardBase.js +90 -14
  28. package/lib/esm/Card/PressableCardBase.js +148 -9
  29. package/lib/esm/Carousel/Carousel.js +106 -51
  30. package/lib/esm/Carousel/CarouselContext.js +10 -4
  31. package/lib/esm/Carousel/CarouselItem/CarouselItem.js +11 -7
  32. package/lib/esm/Carousel/Constants.js +10 -1
  33. package/lib/esm/Checkbox/Checkbox.js +43 -13
  34. package/lib/esm/ExpandCollapse/Control.js +5 -1
  35. package/lib/esm/ExpandCollapse/ExpandCollapse.js +17 -8
  36. package/lib/esm/ExpandCollapse/Panel.js +7 -2
  37. package/lib/esm/IconButton/IconButton.js +10 -5
  38. package/lib/esm/List/List.js +24 -9
  39. package/lib/esm/List/ListItem.js +19 -2
  40. package/lib/esm/List/ListItemBase.js +27 -8
  41. package/lib/esm/List/ListItemMark.js +33 -62
  42. package/lib/esm/List/PressableListItemBase.js +1 -0
  43. package/lib/esm/Modal/Modal.js +21 -11
  44. package/lib/esm/Progress/Progress.js +19 -5
  45. package/lib/esm/Progress/ProgressBar.js +22 -4
  46. package/lib/esm/Progress/ProgressContext.js +5 -0
  47. package/lib/esm/SideNav/Item.js +3 -3
  48. package/lib/esm/SideNav/ItemsGroup.js +45 -20
  49. package/lib/esm/SideNav/SideNav.js +29 -13
  50. package/lib/package.json +2 -2
  51. package/package.json +2 -2
  52. package/src/Card/Card.jsx +29 -7
  53. package/src/Card/CardBase.jsx +97 -11
  54. package/src/Card/PressableCardBase.jsx +135 -9
  55. package/src/Carousel/Carousel.jsx +119 -64
  56. package/src/Carousel/CarouselContext.jsx +12 -4
  57. package/src/Carousel/CarouselItem/CarouselItem.jsx +10 -6
  58. package/src/Carousel/Constants.js +10 -0
  59. package/src/Checkbox/Checkbox.jsx +29 -7
  60. package/src/ExpandCollapse/Control.jsx +1 -1
  61. package/src/ExpandCollapse/ExpandCollapse.jsx +9 -8
  62. package/src/ExpandCollapse/Panel.jsx +10 -2
  63. package/src/IconButton/IconButton.jsx +40 -28
  64. package/src/List/List.jsx +33 -9
  65. package/src/List/ListItem.jsx +33 -11
  66. package/src/List/ListItemBase.jsx +33 -9
  67. package/src/List/ListItemMark.jsx +32 -53
  68. package/src/List/PressableListItemBase.jsx +1 -0
  69. package/src/Modal/Modal.jsx +23 -11
  70. package/src/Progress/Progress.jsx +18 -7
  71. package/src/Progress/ProgressBar.jsx +19 -14
  72. package/src/Progress/ProgressContext.js +5 -0
  73. package/src/SideNav/Item.jsx +3 -3
  74. package/src/SideNav/ItemsGroup.jsx +36 -16
  75. package/src/SideNav/SideNav.jsx +22 -8
@@ -45,12 +45,13 @@ import {
45
45
  LARGE_VIEWPORT_MARGIN,
46
46
  DEFAULT_VIEWPORT_MARGIN,
47
47
  PEEKING_MULTIPLIER,
48
- ACTIVE_INDEX_OFFSET_MULTIPLIER,
49
48
  NEGATIVE_MULTIPLIER,
50
49
  TRANSITION_MODES,
51
50
  SWIPE_RELEASE_STYLES,
52
51
  INSTANT_ANIMATION_DURATION,
53
- DEFAULT_SWIPE_RELEASE_DURATION
52
+ DEFAULT_SWIPE_RELEASE_DURATION,
53
+ POSITION_VARIANTS,
54
+ POSITION_PROPERTIES
54
55
  } from './Constants'
55
56
 
56
57
  const staticStyles = StyleSheet.create({
@@ -112,7 +113,7 @@ const selectHeroContainerStyles = (width, hidden) => ({
112
113
  })
113
114
 
114
115
  const getDynamicPositionProperty = (areStylesAppliedOnPreviousButton) =>
115
- areStylesAppliedOnPreviousButton ? 'left' : 'right'
116
+ areStylesAppliedOnPreviousButton ? POSITION_PROPERTIES.LEFT : POSITION_PROPERTIES.RIGHT
116
117
 
117
118
  const selectControlButtonPositionStyles = ({
118
119
  positionVariant,
@@ -122,24 +123,41 @@ const selectControlButtonPositionStyles = ({
122
123
  enablePeeking,
123
124
  enableDisplayMultipleItemsPerSlide,
124
125
  isAutoPlayEnabled,
125
- viewport
126
+ viewport,
127
+ maxWidth,
128
+ viewportWidth
126
129
  }) => {
127
130
  const styles = {}
128
- if (positionVariant === 'edge') {
129
- styles[positionProperty] = -1 * (buttonWidth / 2)
130
- } else if (positionVariant === 'inside') {
131
- styles[positionProperty] = DEFAULT_POSITION_OFFSET
132
- } else if (positionVariant === 'outside') {
131
+
132
+ let positionOffset = 0
133
+
134
+ if (positionVariant === POSITION_VARIANTS.EDGE) {
135
+ positionOffset = -1 * (buttonWidth / 2)
136
+ } else if (positionVariant === POSITION_VARIANTS.INSIDE) {
137
+ positionOffset = DEFAULT_POSITION_OFFSET
138
+ } else if (positionVariant === POSITION_VARIANTS.OUTSIDE) {
133
139
  if (
134
140
  enablePeeking ||
135
141
  enableDisplayMultipleItemsPerSlide ||
136
142
  (isAutoPlayEnabled && viewport === 'xs')
137
143
  ) {
138
- styles[positionProperty] = 0
144
+ positionOffset = 0
139
145
  } else {
140
- styles[positionProperty] = -1 * (spaceBetweenSlideAndButton + buttonWidth)
146
+ positionOffset = -1 * (spaceBetweenSlideAndButton + buttonWidth)
141
147
  }
142
148
  }
149
+
150
+ if (enablePeeking) {
151
+ if (positionProperty === POSITION_PROPERTIES.RIGHT) {
152
+ const rightMargin = (viewportWidth - maxWidth) / 2
153
+ positionOffset += rightMargin
154
+ } else if (positionProperty === POSITION_PROPERTIES.LEFT) {
155
+ const leftMargin = (viewportWidth - maxWidth) / 2
156
+ positionOffset += leftMargin
157
+ }
158
+ }
159
+
160
+ styles[positionProperty] = positionOffset
143
161
  return styles
144
162
  }
145
163
 
@@ -153,7 +171,9 @@ const selectPreviousNextNavigationButtonStyles = (
153
171
  enablePeeking,
154
172
  enableDisplayMultipleItemsPerSlide,
155
173
  isAutoPlayEnabled,
156
- viewport
174
+ viewport,
175
+ maxWidth,
176
+ viewportWidth
157
177
  ) => {
158
178
  const styles = {
159
179
  zIndex: 1,
@@ -177,7 +197,9 @@ const selectPreviousNextNavigationButtonStyles = (
177
197
  enablePeeking,
178
198
  enableDisplayMultipleItemsPerSlide,
179
199
  isAutoPlayEnabled,
180
- viewport
200
+ viewport,
201
+ maxWidth,
202
+ viewportWidth
181
203
  })
182
204
  }
183
205
  }
@@ -246,7 +268,7 @@ const getMaximumItemsForSlide = (enableDisplayMultipleItemsPerSlide, viewport) =
246
268
  return ITEMS_PER_VIEWPORT_XS_SM
247
269
  }
248
270
 
249
- const selectRootContainerStyles = (enableHero, viewport) => {
271
+ const selectRootContainerStyles = (enableHero, viewport, enablePeeking) => {
250
272
  if (enableHero && viewport === 'xl' && Platform.OS === 'web') {
251
273
  return {
252
274
  alignItems: 'center'
@@ -257,16 +279,26 @@ const selectRootContainerStyles = (enableHero, viewport) => {
257
279
  paddingHorizontal: 16
258
280
  }
259
281
  }
282
+ if (enablePeeking) {
283
+ return {
284
+ width: '100%'
285
+ }
286
+ }
260
287
  return {}
261
288
  }
262
289
 
263
- const selectMainContainerStyles = (enableHero, viewport, maxWidth) => {
264
- if (enableHero && viewport === 'xl' && Platform.OS === 'web') {
290
+ const selectMainContainerStyles = (enableHero, viewport, maxWidth, enablePeeking) => {
291
+ if (enableHero && viewport === 'xl' && Platform.OS === 'web' && !enablePeeking) {
265
292
  return {
266
293
  width: '100%',
267
294
  maxWidth: maxWidth || 1200
268
295
  }
269
296
  }
297
+ if (enablePeeking) {
298
+ return {
299
+ width: '100%'
300
+ }
301
+ }
270
302
  if (maxWidth !== null && maxWidth !== undefined) {
271
303
  return {
272
304
  maxWidth,
@@ -277,16 +309,24 @@ const selectMainContainerStyles = (enableHero, viewport, maxWidth) => {
277
309
  return {}
278
310
  }
279
311
 
280
- const selectNavigationStyles = (tabs, enableHero, viewport) => {
312
+ const selectNavigationStyles = (tabs, enableHero, viewport, enablePeeking, maxWidth) => {
281
313
  let marginHorizontal = 0
282
314
 
283
315
  if (enableHero && tabs) {
284
316
  marginHorizontal = viewport === 'xl' ? LARGE_VIEWPORT_MARGIN : DEFAULT_VIEWPORT_MARGIN
285
317
  }
286
318
 
287
- return {
319
+ const styles = {
288
320
  marginHorizontal
289
321
  }
322
+
323
+ if (enablePeeking && maxWidth) {
324
+ styles.maxWidth = maxWidth
325
+ styles.alignSelf = 'center'
326
+ styles.width = '100%'
327
+ }
328
+
329
+ return styles
290
330
  }
291
331
 
292
332
  /**
@@ -295,22 +335,16 @@ const selectNavigationStyles = (tabs, enableHero, viewport) => {
295
335
  * @param {number} containerWidth - The width of the carousel container.
296
336
  * @param {boolean} enablePeeking - Flag indicating whether peeking is enabled.
297
337
  * @param {Object} viewport - The viewport configuration object used to determine peeking properties.
298
- * @param {React.MutableRefObject<number>} activeIndexRef - A ref object holding the current active index of the carousel.
338
+ * @param {number} maxWidth - The maximum width constraint for the carousel content.
299
339
  * @returns {number} The calculated final width of the carousel container.
300
340
  */
301
- const calculateFinalWidth = (containerWidth, enablePeeking, viewport, activeIndexRef) => {
341
+ const calculateFinalWidth = (containerWidth, enablePeeking, viewport, maxWidth) => {
302
342
  let finalWidth = containerWidth
303
343
 
304
344
  if (enablePeeking) {
305
- const { peekingGap, peekingMiddleSpace, peekingMarginLeft } = getPeekingProps(viewport)
306
- const slideWide =
307
- containerWidth - (peekingMiddleSpace * PEEKING_MULTIPLIER + peekingGap * PEEKING_MULTIPLIER)
308
-
309
- if (activeIndexRef.current === 0) {
310
- finalWidth = slideWide + peekingMarginLeft - peekingMiddleSpace
311
- } else {
312
- finalWidth = slideWide + peekingGap
313
- }
345
+ const { peekingGap, peekingMiddleSpace } = getPeekingProps(viewport)
346
+ const baseWidth = maxWidth || containerWidth
347
+ finalWidth = baseWidth - peekingMiddleSpace * PEEKING_MULTIPLIER + peekingGap
314
348
  }
315
349
 
316
350
  return finalWidth
@@ -431,7 +465,15 @@ const Carousel = React.forwardRef(
431
465
 
432
466
  const contentMaxWidthValue = useResponsiveProp(contentMaxWidth)
433
467
  const responsiveWidth = useResponsiveProp(themeOptions?.contentMaxWidth)
434
- const maxWidth = resolveContentMaxWidth(contentMaxWidthValue, responsiveWidth)
468
+
469
+ let maxWidth = null
470
+ if (enablePeeking || contentMaxWidth !== undefined) {
471
+ maxWidth =
472
+ contentMaxWidthValue === undefined
473
+ ? responsiveWidth
474
+ : resolveContentMaxWidth(contentMaxWidthValue, responsiveWidth)
475
+ }
476
+
435
477
  const totalItems = getTotalItems(enableDisplayMultipleItemsPerSlide, childrenArray, viewport)
436
478
  const autoPlayFeatureEnabled =
437
479
  autoPlay && slideDuration > 0 && transitionDuration > 0 && totalItems > 1
@@ -494,8 +536,17 @@ const Carousel = React.forwardRef(
494
536
  const isSwiping = React.useRef(false)
495
537
  const autoPlayRef = React.useRef(null)
496
538
 
539
+ const [rootContainerLayout, setRootContainerLayout] = React.useState({
540
+ x: 0,
541
+ y: 0,
542
+ width: 0,
543
+ height: 0
544
+ })
545
+ const rootContainerLayoutRef = React.useRef(rootContainerLayout)
546
+
497
547
  const isFirstSlide = !activeIndex
498
548
  const isLastSlide = activeIndex + 1 >= totalItems
549
+ const currentViewportWidth = rootContainerLayout.width
499
550
 
500
551
  const handleAnimationStart = React.useCallback(
501
552
  (...args) => {
@@ -518,21 +569,16 @@ const Carousel = React.forwardRef(
518
569
 
519
570
  const updateOffset = React.useCallback(() => {
520
571
  if (enablePeeking) {
521
- const { peekingGap, peekingMiddleSpace, peekingMarginLeft } = getPeekingProps(viewport)
572
+ const { peekingGap, peekingMiddleSpace } = getPeekingProps(viewport)
522
573
 
523
574
  let finalWidth
524
- const slideWide =
525
- containerLayoutRef.current.width -
526
- (peekingMiddleSpace * PEEKING_MULTIPLIER + peekingGap * PEEKING_MULTIPLIER)
575
+ const baseWidth = maxWidth || containerLayoutRef.current.width
576
+ const slideWide = baseWidth - peekingMiddleSpace * PEEKING_MULTIPLIER
527
577
 
528
578
  if (activeIndexRef.current === 0) {
529
579
  finalWidth = 0
530
580
  } else {
531
- finalWidth =
532
- slideWide +
533
- peekingMarginLeft -
534
- peekingMiddleSpace +
535
- (slideWide + peekingGap) * (activeIndexRef.current - ACTIVE_INDEX_OFFSET_MULTIPLIER)
581
+ finalWidth = (slideWide + peekingGap) * activeIndexRef.current
536
582
  }
537
583
 
538
584
  animatedX.current = finalWidth * NEGATIVE_MULTIPLIER
@@ -558,7 +604,7 @@ const Carousel = React.forwardRef(
558
604
  })
559
605
  heroPan.setValue({ x: 0, y: 0 })
560
606
  }
561
- }, [pan, animatedX, heroPan, heroAnimatedX, enableHero, viewport, enablePeeking])
607
+ }, [pan, animatedX, heroPan, heroAnimatedX, enableHero, viewport, enablePeeking, maxWidth])
562
608
 
563
609
  const animate = React.useCallback(
564
610
  (panToAnimate, toValue, toIndex, isSwipeRelease = false) => {
@@ -664,7 +710,7 @@ const Carousel = React.forwardRef(
664
710
  containerLayoutRef.current.width,
665
711
  enablePeeking,
666
712
  viewport,
667
- activeIndexRef
713
+ maxWidth
668
714
  )
669
715
 
670
716
  toValue.x = finalWidth * -1 * calcDelta
@@ -710,7 +756,8 @@ const Carousel = React.forwardRef(
710
756
  enablePeeking,
711
757
  pan,
712
758
  heroPan,
713
- enableHero
759
+ enableHero,
760
+ maxWidth
714
761
  ]
715
762
  )
716
763
 
@@ -767,6 +814,10 @@ const Carousel = React.forwardRef(
767
814
  heroContainerLayoutRef.current = heroContainerLayout
768
815
  }, [heroContainerLayout])
769
816
 
817
+ React.useEffect(() => {
818
+ rootContainerLayoutRef.current = rootContainerLayout
819
+ }, [rootContainerLayout])
820
+
770
821
  React.useEffect(() => {
771
822
  pan.x.addListener(({ value }) => {
772
823
  animatedX.current = value
@@ -849,6 +900,12 @@ const Carousel = React.forwardRef(
849
900
  }
850
901
  }) => setPreviousNextNavigationButtonWidth(width)
851
902
 
903
+ const onRootContainerLayout = ({
904
+ nativeEvent: {
905
+ layout: { x, y, width, height }
906
+ }
907
+ }) => setRootContainerLayout((prevState) => ({ ...prevState, x, y, width, height }))
908
+
852
909
  const isSwipeAllowed = React.useCallback(() => {
853
910
  if (totalItems === 1) {
854
911
  return false
@@ -1071,8 +1128,11 @@ const Carousel = React.forwardRef(
1071
1128
  )
1072
1129
 
1073
1130
  return (
1074
- <View style={selectRootContainerStyles(enableHero, viewport)}>
1075
- <View style={selectMainContainerStyles(enableHero, viewport, maxWidth)}>
1131
+ <View
1132
+ style={selectRootContainerStyles(enableHero, viewport, enablePeeking)}
1133
+ onLayout={onRootContainerLayout}
1134
+ >
1135
+ <View style={selectMainContainerStyles(enableHero, viewport, maxWidth, enablePeeking)}>
1076
1136
  <CarouselProvider
1077
1137
  activeIndex={activeIndex}
1078
1138
  goTo={goTo}
@@ -1087,6 +1147,8 @@ const Carousel = React.forwardRef(
1087
1147
  enableDisplayMultipleItemsPerSlide,
1088
1148
  viewport
1089
1149
  )}
1150
+ maxWidth={maxWidth}
1151
+ viewportWidth={currentViewportWidth}
1090
1152
  >
1091
1153
  <View
1092
1154
  style={[
@@ -1113,7 +1175,9 @@ const Carousel = React.forwardRef(
1113
1175
  enablePeeking,
1114
1176
  enableDisplayMultipleItemsPerSlide,
1115
1177
  isAutoPlayEnabled,
1116
- viewport
1178
+ viewport,
1179
+ maxWidth,
1180
+ viewportWidth: currentViewportWidth
1117
1181
  })
1118
1182
  ]}
1119
1183
  >
@@ -1139,7 +1203,9 @@ const Carousel = React.forwardRef(
1139
1203
  enablePeeking,
1140
1204
  enableDisplayMultipleItemsPerSlide,
1141
1205
  isAutoPlayEnabled,
1142
- viewport
1206
+ viewport,
1207
+ maxWidth,
1208
+ currentViewportWidth
1143
1209
  )}
1144
1210
  testID="previous-button-container"
1145
1211
  >
@@ -1192,22 +1258,7 @@ const Carousel = React.forwardRef(
1192
1258
  let hidden = !isAnimating && index !== activeIndex
1193
1259
 
1194
1260
  if (enablePeeking && !isAnimating) {
1195
- if (enableDisplayMultipleItemsPerSlide) {
1196
- const maxItemsForSlide = getMaximumItemsForSlide(
1197
- enableDisplayMultipleItemsPerSlide,
1198
- viewport
1199
- )
1200
- if (
1201
- index >= activeIndex * maxItemsForSlide - 1 &&
1202
- index < activeIndex * maxItemsForSlide + maxItemsForSlide + 1
1203
- ) {
1204
- hidden = false
1205
- } else {
1206
- hidden = true
1207
- }
1208
- } else if (index >= activeIndex - 1 && index <= activeIndex + 1) {
1209
- hidden = false
1210
- }
1261
+ hidden = false
1211
1262
  } else if (
1212
1263
  !enablePeeking &&
1213
1264
  enableDisplayMultipleItemsPerSlide &&
@@ -1250,7 +1301,9 @@ const Carousel = React.forwardRef(
1250
1301
  enablePeeking,
1251
1302
  enableDisplayMultipleItemsPerSlide,
1252
1303
  isAutoPlayEnabled,
1253
- viewport
1304
+ viewport,
1305
+ maxWidth,
1306
+ currentViewportWidth
1254
1307
  )}
1255
1308
  testID="next-button-container"
1256
1309
  >
@@ -1268,7 +1321,9 @@ const Carousel = React.forwardRef(
1268
1321
  </View>
1269
1322
  ) : null}
1270
1323
  </View>
1271
- <View style={selectNavigationStyles(tabs, enableHero, viewport)}>
1324
+ <View
1325
+ style={selectNavigationStyles(tabs, enableHero, viewport, enablePeeking, maxWidth)}
1326
+ >
1272
1327
  {showPanelNavigation ? activePanelNavigation : null}
1273
1328
  </View>
1274
1329
  </CarouselProvider>
@@ -14,7 +14,9 @@ const CarouselProvider = ({
14
14
  themeTokens,
15
15
  totalItems,
16
16
  width,
17
- maximumItemsForSlide
17
+ maximumItemsForSlide,
18
+ maxWidth,
19
+ viewportWidth
18
20
  }) => {
19
21
  const value = React.useMemo(
20
22
  () => ({
@@ -26,7 +28,9 @@ const CarouselProvider = ({
26
28
  themeTokens,
27
29
  totalItems,
28
30
  width,
29
- maximumItemsForSlide
31
+ maximumItemsForSlide,
32
+ maxWidth,
33
+ viewportWidth
30
34
  }),
31
35
  [
32
36
  activeIndex,
@@ -37,7 +41,9 @@ const CarouselProvider = ({
37
41
  totalItems,
38
42
  themeTokens,
39
43
  width,
40
- maximumItemsForSlide
44
+ maximumItemsForSlide,
45
+ maxWidth,
46
+ viewportWidth
41
47
  ]
42
48
  )
43
49
  return <CarouselContext.Provider value={value}>{children}</CarouselContext.Provider>
@@ -61,7 +67,9 @@ CarouselProvider.propTypes = {
61
67
  themeTokens: getTokensPropType('Carousel'),
62
68
  totalItems: PropTypes.number.isRequired,
63
69
  width: PropTypes.number.isRequired,
64
- maximumItemsForSlide: PropTypes.number
70
+ maximumItemsForSlide: PropTypes.number,
71
+ maxWidth: PropTypes.number,
72
+ viewportWidth: PropTypes.number
65
73
  }
66
74
 
67
75
  export { CarouselProvider, useCarousel }
@@ -18,27 +18,28 @@ const selectContainerStyle = ({
18
18
  width,
19
19
  elementIndex,
20
20
  enablePeeking,
21
- peekingMarginLeft,
22
21
  peekingGap,
23
22
  hidden,
24
23
  enableDisplayMultipleItemsPerSlide,
25
24
  viewport,
26
- peekingMiddleSpace
25
+ peekingMiddleSpace,
26
+ maxWidth,
27
+ viewportWidth
27
28
  }) => {
28
29
  let adjustedWidth = width
29
30
  let marginLeft = 0
30
31
 
31
32
  if (enablePeeking) {
32
33
  const isFirst = elementIndex === 0
33
- adjustedWidth = width - (peekingMiddleSpace * 2 + peekingGap * 2)
34
+ const baseWidth = maxWidth || width
35
+ adjustedWidth = baseWidth - peekingMiddleSpace * 2
34
36
  if (isFirst) {
35
- marginLeft = peekingMarginLeft
37
+ marginLeft = peekingMiddleSpace + (viewportWidth - maxWidth) / 2
36
38
  } else {
37
39
  marginLeft = peekingGap
38
40
  }
39
41
  }
40
42
 
41
- // Adjust width and margins for multiple items per slide.
42
43
  if (enableDisplayMultipleItemsPerSlide) {
43
44
  switch (viewport) {
44
45
  case 'xs':
@@ -102,7 +103,8 @@ const CarouselItem = React.forwardRef(
102
103
  },
103
104
  ref
104
105
  ) => {
105
- const { width, activeIndex, goTo, maximumItemsForSlide } = useCarousel()
106
+ const { width, activeIndex, goTo, maximumItemsForSlide, maxWidth, viewportWidth } =
107
+ useCarousel()
106
108
 
107
109
  const selectedProps = selectProps({
108
110
  ...rest,
@@ -162,6 +164,8 @@ const CarouselItem = React.forwardRef(
162
164
  enablePeeking,
163
165
  enableDisplayMultipleItemsPerSlide,
164
166
  viewport,
167
+ maxWidth,
168
+ viewportWidth,
165
169
  ...peekingProps
166
170
  })}
167
171
  {...selectedProps}
@@ -23,3 +23,13 @@ export const SWIPE_RELEASE_STYLES = {
23
23
 
24
24
  export const INSTANT_ANIMATION_DURATION = 1
25
25
  export const DEFAULT_SWIPE_RELEASE_DURATION = 500
26
+ export const POSITION_VARIANTS = {
27
+ EDGE: 'edge',
28
+ INSIDE: 'inside',
29
+ OUTSIDE: 'outside'
30
+ }
31
+
32
+ export const POSITION_PROPERTIES = {
33
+ LEFT: 'left',
34
+ RIGHT: 'right'
35
+ }
@@ -109,6 +109,25 @@ const selectFeedbackTokens = ({ feedbackMarginBottom, feedbackMarginTop, feedbac
109
109
  feedbackMarginTop
110
110
  })
111
111
 
112
+ const selectPressableStyles = ({
113
+ padding,
114
+ paddingLeft,
115
+ paddingRight,
116
+ paddingTop,
117
+ paddingBottom
118
+ }) => ({
119
+ padding,
120
+ paddingLeft,
121
+ paddingRight,
122
+ paddingTop,
123
+ paddingBottom
124
+ })
125
+
126
+ const selectContainerStyles = ({ iconContainerHeight, iconContainerWidth }) => ({
127
+ height: iconContainerHeight,
128
+ width: iconContainerWidth
129
+ })
130
+
112
131
  /**
113
132
  * Basic Checkbox component.
114
133
  *
@@ -160,6 +179,7 @@ const Checkbox = React.forwardRef(
160
179
  tokens,
161
180
  value,
162
181
  variant,
182
+ testID,
163
183
  ...rest
164
184
  },
165
185
  ref
@@ -211,24 +231,22 @@ const Checkbox = React.forwardRef(
211
231
  <View style={staticStyles.wrapper} ref={ref}>
212
232
  <StackView direction={feedbackPosition === 'top' ? 'column-reverse' : 'column'} space={0}>
213
233
  <Pressable
234
+ testID={testID && `${testID}-pressable`}
214
235
  disabled={inactive}
215
236
  onKeyDown={handleKeyDown}
216
237
  onPress={handleChange}
217
238
  {...selectedProps}
218
- style={staticStyles.removeOutline}
239
+ style={[staticStyles.removeOutline, selectPressableStyles(defaultTokens)]}
219
240
  >
220
241
  {({ focused: focus, hovered: hover, pressed }) => {
221
242
  const { icon: IconComponent, ...stateTokens } = getTokens({ focus, hover, pressed })
222
243
  const iconTokens = selectIconTokens(stateTokens)
223
244
  const labelStyles = selectLabelStyles(stateTokens, themeOptions)
224
- const alignWithLabel = label
225
- ? [staticStyles.alignWithLabel, { height: labelStyles.lineHeight }]
226
- : null
227
245
 
228
246
  return (
229
247
  <StackView space={0}>
230
248
  <View style={staticStyles.container}>
231
- <View style={alignWithLabel}>
249
+ <View style={[staticStyles.iconContainer, selectContainerStyles(stateTokens)]}>
232
250
  <View
233
251
  style={[
234
252
  staticStyles.defaultInputStyles,
@@ -335,7 +353,11 @@ Checkbox.propTypes = {
335
353
  /**
336
354
  * An optional Checkbox description.
337
355
  */
338
- description: PropTypes.string
356
+ description: PropTypes.string,
357
+ /**
358
+ * A identifier for testing purposes.
359
+ */
360
+ testID: PropTypes.string
339
361
  }
340
362
 
341
363
  export default Checkbox
@@ -344,6 +366,6 @@ const staticStyles = StyleSheet.create({
344
366
  wrapper: { backgroundColor: 'transparent' },
345
367
  container: { flexDirection: 'row', alignItems: 'center' },
346
368
  defaultInputStyles: { alignItems: 'center', justifyContent: 'center' },
347
- alignWithLabel: { alignSelf: 'flex-start', justifyContent: 'center' },
369
+ iconContainer: { display: 'flex', justifyContent: 'center', alignItems: 'center' },
348
370
  removeOutline: { outlineStyle: 'none' }
349
371
  })
@@ -50,7 +50,7 @@ function selectIconContainerStyles({ iconGap, iconPaddingTop, iconPosition }) {
50
50
  const paddingSide = iconPosition === 'right' ? 'paddingLeft' : 'paddingRight'
51
51
  return {
52
52
  [paddingSide]: iconGap,
53
- paddingTop: iconPaddingTop
53
+ ...(iconPaddingTop && { transform: [{ translateY: iconPaddingTop }] })
54
54
  }
55
55
  }
56
56
 
@@ -20,13 +20,14 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([
20
20
  contentfulProps
21
21
  ])
22
22
 
23
- function selectBorderStyles(tokens) {
24
- return {
25
- borderBottomWidth: tokens.borderWidth,
26
- borderBottomStyle: tokens.borderStyle,
27
- borderBottomColor: tokens.borderColor
28
- }
29
- }
23
+ const selectWrapperStyles = ({ borderWidth, borderTopWidth, borderStyle, borderColor }) => ({
24
+ borderStyle,
25
+ borderColor,
26
+ borderTopWidth,
27
+ borderBottomWidth: borderWidth,
28
+ borderBottomStyle: borderStyle,
29
+ borderBottomColor: borderColor
30
+ })
30
31
 
31
32
  /**
32
33
  * Flexible base component for lists where some or all items are collapsible headers.
@@ -55,7 +56,7 @@ const ExpandCollapse = React.forwardRef(
55
56
 
56
57
  return (
57
58
  <View style={staticStyles.container} ref={ref} {...selectProps(rest)} dataSet={dataSet}>
58
- <View style={selectBorderStyles(themeTokens)}>
59
+ <View style={selectWrapperStyles(themeTokens)}>
59
60
  {typeof children === 'function'
60
61
  ? children({ openIds, onToggle, resetValues, setValues, unsetValues, instanceId })
61
62
  : children}
@@ -96,6 +96,7 @@ const ExpandCollapsePanel = React.forwardRef(
96
96
  controlRef,
97
97
  content,
98
98
  copy = 'en',
99
+ disableMobileScrollBuffer = false,
99
100
  ...rest
100
101
  },
101
102
  ref
@@ -118,7 +119,10 @@ const ExpandCollapsePanel = React.forwardRef(
118
119
 
119
120
  // on mobile devices we require a scroll buffer equal to the font size
120
121
  // to avoid triggering scrolling unnecessarily
121
- const mobileScrollBuffer = Platform.OS === 'web' ? 0 : selectTextStyles(themeTokens)?.fontSize
122
+ const mobileScrollBuffer =
123
+ Platform.OS === 'web' || disableMobileScrollBuffer
124
+ ? 0
125
+ : selectTextStyles(themeTokens)?.fontSize
122
126
 
123
127
  const handleControlPress = (event) => {
124
128
  onToggle?.(panelId, event)
@@ -287,7 +291,11 @@ ExpandCollapsePanel.propTypes = {
287
291
  /**
288
292
  * A boolean prop to determine if the panel is a content panel or not. If true, the panel will not have a control
289
293
  */
290
- content: PropTypes.bool
294
+ content: PropTypes.bool,
295
+ /**
296
+ * A boolean prop to disable the extra scroll buffer on mobile devices (only applicable on iOS/Android, ignored on web)
297
+ */
298
+ disableMobileScrollBuffer: PropTypes.bool
291
299
  }
292
300
 
293
301
  export default ExpandCollapsePanel