@hero-design/rn 8.57.0 → 8.58.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 (28) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +25 -0
  3. package/es/index.js +172 -94
  4. package/lib/index.js +172 -94
  5. package/package.json +6 -6
  6. package/src/components/Calendar/__tests__/index.spec.tsx +5 -5
  7. package/src/components/Carousel/CardCarousel.tsx +7 -9
  8. package/src/components/Carousel/CarouselItem.tsx +26 -14
  9. package/src/components/Carousel/StyledCarousel.tsx +2 -3
  10. package/src/components/Carousel/__tests__/__snapshots__/index.spec.tsx.snap +494 -48
  11. package/src/components/Carousel/__tests__/index.spec.tsx +34 -1
  12. package/src/components/Carousel/types.ts +3 -3
  13. package/src/components/DatePicker/__tests__/DatePickerCalendar.spec.tsx +32 -29
  14. package/src/components/Tabs/ScrollableTabsHeader/ScrollableTabsHeader.tsx +10 -12
  15. package/src/components/Tabs/__tests__/__snapshots__/ScrollableTabs.spec.tsx.snap +18 -6
  16. package/src/components/Tabs/__tests__/__snapshots__/ScrollableTabsHeader.spec.tsx.snap +12 -4
  17. package/src/components/TextInput/__tests__/index.spec.tsx +148 -1
  18. package/src/components/TextInput/index.tsx +135 -57
  19. package/src/components/Toast/ToastContext.ts +20 -2
  20. package/src/components/Toast/ToastProvider.tsx +7 -4
  21. package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +0 -1
  22. package/src/theme/components/carousel.ts +0 -1
  23. package/types/components/Carousel/CardCarousel.d.ts +1 -0
  24. package/types/components/Carousel/StyledCarousel.d.ts +2 -2
  25. package/types/components/Carousel/types.d.ts +3 -3
  26. package/types/components/TextInput/index.d.ts +29 -1
  27. package/types/components/Toast/ToastContext.d.ts +1 -0
  28. package/types/theme/components/carousel.d.ts +0 -1
package/lib/index.js CHANGED
@@ -2433,7 +2433,6 @@ var getCardTheme = function getCardTheme(theme) {
2433
2433
 
2434
2434
  var getCarouselTheme = function getCarouselTheme(theme) {
2435
2435
  var space = {
2436
- headingMarginTop: theme.space.small,
2437
2436
  headingMarginBottom: theme.space.medium,
2438
2437
  footerPaddingHorizontal: theme.space.large,
2439
2438
  footerPaddingVertical: theme.space.medium,
@@ -12069,6 +12068,9 @@ var ITEM_WIDTH_RATE = 0.85;
12069
12068
  */
12070
12069
  var VIEW_POSITION_CENTER = 0.5;
12071
12070
 
12071
+ var getCardCarouselValidIndex = function getCardCarouselValidIndex(index, length) {
12072
+ return Math.min(Math.max(index, 0), length - 1);
12073
+ };
12072
12074
  var CardCarousel = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
12073
12075
  var onItemIndexChange = _ref.onItemIndexChange,
12074
12076
  items = _ref.items,
@@ -12095,18 +12097,13 @@ var CardCarousel = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
12095
12097
  var viewPosition = reactNative.Platform.OS === 'ios' ? VIEW_POSITION_CENTER : undefined;
12096
12098
  var _snapToIndex = React.useCallback(function (index) {
12097
12099
  var _carouselRef$current;
12098
- var validIndex = 0;
12099
- if (index >= items.length) {
12100
- validIndex = items.length - 1;
12101
- } else if (index >= 0) {
12102
- validIndex = index;
12103
- }
12100
+ var validIndex = getCardCarouselValidIndex(index, items.length);
12104
12101
  (_carouselRef$current = carouselRef.current) === null || _carouselRef$current === void 0 || _carouselRef$current.scrollToIndex({
12105
12102
  index: validIndex,
12106
12103
  animated: true,
12107
12104
  viewPosition: viewPosition
12108
12105
  });
12109
- }, [carouselRef, itemWidth]);
12106
+ }, [items.length, viewPosition]);
12110
12107
  /*
12111
12108
  * snap to the next index. If the curent index is the last one, snap to the first one.
12112
12109
  */
@@ -12121,7 +12118,7 @@ var CardCarousel = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
12121
12118
  animated: true,
12122
12119
  viewPosition: viewPosition
12123
12120
  });
12124
- }, [carouselRef, currentIndex, itemWidth, items.length]);
12121
+ }, [currentIndex, items.length, viewPosition]);
12125
12122
  React__default["default"].useImperativeHandle(ref, function () {
12126
12123
  return {
12127
12124
  snapToIndex: function snapToIndex(index) {
@@ -12271,7 +12268,6 @@ var StyledCarouselView = index$9(reactNative.View)(function () {
12271
12268
  var StyledCarouselHeading = index$9(Typography.Title)(function (_ref2) {
12272
12269
  var theme = _ref2.theme;
12273
12270
  return {
12274
- marginTop: theme.__hd__.carousel.space.headingMarginTop,
12275
12271
  marginBottom: theme.__hd__.carousel.space.headingMarginBottom
12276
12272
  };
12277
12273
  });
@@ -12335,22 +12331,37 @@ var CarouselItem = function CarouselItem(_ref) {
12335
12331
  content = _ref.content,
12336
12332
  heading = _ref.heading,
12337
12333
  body = _ref.body;
12334
+ var theme = useTheme$1();
12335
+ var ImageComponent = React__default["default"].useMemo(function () {
12336
+ if (image) {
12337
+ if (isCarouselImageProps(image)) {
12338
+ return /*#__PURE__*/React__default["default"].createElement(StyledCustomSizeCarouselImage, {
12339
+ source: image,
12340
+ height: image.height,
12341
+ width: image.width,
12342
+ resizeMode: image.resizeMode,
12343
+ style: {
12344
+ marginBottom: theme.space.medium
12345
+ }
12346
+ });
12347
+ }
12348
+ return /*#__PURE__*/React__default["default"].createElement(StyledCarouselImage, {
12349
+ source: typeof image === 'string' ? {
12350
+ uri: image
12351
+ } : image,
12352
+ style: {
12353
+ marginBottom: theme.space.medium
12354
+ }
12355
+ });
12356
+ }
12357
+ return null;
12358
+ }, [image]);
12338
12359
  return /*#__PURE__*/React__default["default"].createElement(Box, {
12339
12360
  style: {
12340
12361
  width: width
12341
12362
  }
12342
- }, image && (isCarouselImageProps(image) ? /*#__PURE__*/React__default["default"].createElement(StyledCustomSizeCarouselImage, {
12343
- source: image,
12344
- height: image.height,
12345
- width: image.width,
12346
- resizeMode: image.resizeMode
12347
- }) : /*#__PURE__*/React__default["default"].createElement(StyledCarouselImage, {
12348
- source: typeof image === 'string' ? {
12349
- uri: image
12350
- } : image
12351
- })), /*#__PURE__*/React__default["default"].createElement(StyledCarouselContentWrapper, {
12352
- paddingHorizontal: "large",
12353
- marginTop: "large",
12363
+ }, ImageComponent, /*#__PURE__*/React__default["default"].createElement(StyledCarouselContentWrapper, {
12364
+ paddingHorizontal: "medium",
12354
12365
  width: width
12355
12366
  }, content, /*#__PURE__*/React__default["default"].createElement(StyledCarouselHeading, {
12356
12367
  level: "h1",
@@ -12876,38 +12887,96 @@ var getState$1 = function getState(_ref) {
12876
12887
  // https://github.com/callstack/react-native-paper/pull/3331
12877
12888
  var EMPTY_PLACEHOLDER_VALUE = ' ';
12878
12889
  var LABEL_ANIMATION_DURATION = 150;
12879
- var TextInput = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
12880
- var _ref3;
12881
- var label = _ref2.label,
12882
- prefix = _ref2.prefix,
12883
- suffix = _ref2.suffix,
12884
- style = _ref2.style,
12885
- textStyle = _ref2.textStyle,
12886
- testID = _ref2.testID,
12887
- accessibilityLabelledBy = _ref2.accessibilityLabelledBy,
12888
- error = _ref2.error,
12889
- required = _ref2.required,
12890
- _ref2$editable = _ref2.editable,
12891
- editable = _ref2$editable === void 0 ? true : _ref2$editable,
12892
- _ref2$disabled = _ref2.disabled,
12893
- disabled = _ref2$disabled === void 0 ? false : _ref2$disabled,
12894
- _ref2$loading = _ref2.loading,
12895
- loading = _ref2$loading === void 0 ? false : _ref2$loading,
12896
- maxLength = _ref2.maxLength,
12897
- _ref2$hideCharacterCo = _ref2.hideCharacterCount,
12898
- hideCharacterCount = _ref2$hideCharacterCo === void 0 ? false : _ref2$hideCharacterCo,
12899
- helpText = _ref2.helpText,
12900
- value = _ref2.value,
12901
- defaultValue = _ref2.defaultValue,
12902
- renderInputValue = _ref2.renderInputValue,
12903
- _ref2$allowFontScalin = _ref2.allowFontScaling,
12904
- allowFontScaling = _ref2$allowFontScalin === void 0 ? false : _ref2$allowFontScalin,
12905
- _ref2$variant = _ref2.variant,
12906
- variant = _ref2$variant === void 0 ? 'text' : _ref2$variant,
12907
- nativeProps = _objectWithoutProperties(_ref2, _excluded$j);
12908
- var displayText = (_ref3 = value !== undefined ? value : defaultValue) !== null && _ref3 !== void 0 ? _ref3 : '';
12909
- var isEmptyValue = displayText.length === 0;
12890
+ var renderErrorOrHelpText = function renderErrorOrHelpText(_ref2) {
12891
+ var error = _ref2.error,
12892
+ helpText = _ref2.helpText;
12893
+ return error ? /*#__PURE__*/React__default["default"].createElement(StyledErrorContainer$2, null, /*#__PURE__*/React__default["default"].createElement(Icon, {
12894
+ testID: "input-error-icon",
12895
+ icon: "circle-info",
12896
+ size: "xsmall",
12897
+ intent: "danger"
12898
+ }), /*#__PURE__*/React__default["default"].createElement(StyledError, {
12899
+ testID: "input-error-message"
12900
+ }, error)) : !!helpText && /*#__PURE__*/React__default["default"].createElement(StyledHelperText, null, helpText);
12901
+ };
12902
+ var renderInput = function renderInput(_ref3) {
12903
+ var variant = _ref3.variant,
12904
+ nativeInputProps = _ref3.nativeInputProps,
12905
+ renderInputValue = _ref3.renderInputValue,
12906
+ ref = _ref3.ref;
12907
+ return renderInputValue ? renderInputValue(nativeInputProps) : /*#__PURE__*/React__default["default"].createElement(StyledTextInput, _extends$1({}, nativeInputProps, {
12908
+ themeVariant: variant,
12909
+ multiline: variant === 'textarea' || nativeInputProps.multiline,
12910
+ ref: ref
12911
+ }));
12912
+ };
12913
+ var renderSuffix = function renderSuffix(_ref4) {
12914
+ var state = _ref4.state,
12915
+ loading = _ref4.loading,
12916
+ suffix = _ref4.suffix;
12910
12917
  var actualSuffix = loading ? 'loading' : suffix;
12918
+ return typeof actualSuffix === 'string' ? /*#__PURE__*/React__default["default"].createElement(Icon, {
12919
+ intent: state === 'disabled' ? 'disabled-text' : 'text',
12920
+ testID: "input-suffix",
12921
+ icon: actualSuffix,
12922
+ spin: actualSuffix === 'loading',
12923
+ size: "medium"
12924
+ }) : suffix;
12925
+ };
12926
+ var renderPrefix = function renderPrefix(_ref5) {
12927
+ var state = _ref5.state,
12928
+ prefix = _ref5.prefix;
12929
+ return typeof prefix === 'string' ? /*#__PURE__*/React__default["default"].createElement(Icon, {
12930
+ intent: state === 'disabled' ? 'disabled-text' : 'text',
12931
+ testID: "input-prefix",
12932
+ icon: prefix,
12933
+ size: "xsmall"
12934
+ }) : prefix;
12935
+ };
12936
+ var renderMaxLengthMessage = function renderMaxLengthMessage(_ref6) {
12937
+ var maxLength = _ref6.maxLength,
12938
+ state = _ref6.state,
12939
+ currentLength = _ref6.currentLength,
12940
+ hideCharacterCount = _ref6.hideCharacterCount;
12941
+ var shouldShowMaxLength = maxLength !== undefined && !hideCharacterCount;
12942
+ return shouldShowMaxLength && /*#__PURE__*/React__default["default"].createElement(StyledMaxLengthMessage, {
12943
+ themeState: state
12944
+ }, currentLength, "/", maxLength);
12945
+ };
12946
+ var getDisplayText = function getDisplayText(value, defaultValue) {
12947
+ var _ref7;
12948
+ return (_ref7 = value !== undefined ? value : defaultValue) !== null && _ref7 !== void 0 ? _ref7 : '';
12949
+ };
12950
+ var TextInput = /*#__PURE__*/React.forwardRef(function (_ref8, ref) {
12951
+ var label = _ref8.label,
12952
+ prefix = _ref8.prefix,
12953
+ suffix = _ref8.suffix,
12954
+ style = _ref8.style,
12955
+ textStyle = _ref8.textStyle,
12956
+ testID = _ref8.testID,
12957
+ accessibilityLabelledBy = _ref8.accessibilityLabelledBy,
12958
+ error = _ref8.error,
12959
+ required = _ref8.required,
12960
+ _ref8$editable = _ref8.editable,
12961
+ editable = _ref8$editable === void 0 ? true : _ref8$editable,
12962
+ _ref8$disabled = _ref8.disabled,
12963
+ disabled = _ref8$disabled === void 0 ? false : _ref8$disabled,
12964
+ _ref8$loading = _ref8.loading,
12965
+ loading = _ref8$loading === void 0 ? false : _ref8$loading,
12966
+ maxLength = _ref8.maxLength,
12967
+ _ref8$hideCharacterCo = _ref8.hideCharacterCount,
12968
+ hideCharacterCount = _ref8$hideCharacterCo === void 0 ? false : _ref8$hideCharacterCo,
12969
+ helpText = _ref8.helpText,
12970
+ value = _ref8.value,
12971
+ defaultValue = _ref8.defaultValue,
12972
+ renderInputValue = _ref8.renderInputValue,
12973
+ _ref8$allowFontScalin = _ref8.allowFontScaling,
12974
+ allowFontScaling = _ref8$allowFontScalin === void 0 ? false : _ref8$allowFontScalin,
12975
+ _ref8$variant = _ref8.variant,
12976
+ variant = _ref8$variant === void 0 ? 'text' : _ref8$variant,
12977
+ nativeProps = _objectWithoutProperties(_ref8, _excluded$j);
12978
+ var displayText = getDisplayText(value, defaultValue);
12979
+ var isEmptyValue = displayText.length === 0;
12911
12980
  var _React$useState = React__default["default"].useState({
12912
12981
  height: 0,
12913
12982
  width: 0
@@ -12935,7 +13004,6 @@ var TextInput = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
12935
13004
  isFocused: isFocused,
12936
13005
  isEmptyValue: isEmptyValue
12937
13006
  });
12938
- var shouldShowMaxLength = maxLength !== undefined && !hideCharacterCount;
12939
13007
  var theme = useTheme();
12940
13008
  var focusAnimation = React.useRef(new reactNative.Animated.Value(0)).current;
12941
13009
  React.useEffect(function () {
@@ -13073,12 +13141,10 @@ var TextInput = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
13073
13141
  }, borderStyle]
13074
13142
  }), /*#__PURE__*/React__default["default"].createElement(reactNative.View, {
13075
13143
  onLayout: onPrefixLayout
13076
- }, typeof prefix === 'string' ? /*#__PURE__*/React__default["default"].createElement(Icon, {
13077
- intent: state === 'disabled' ? 'disabled-text' : 'text',
13078
- testID: "input-prefix",
13079
- icon: prefix,
13080
- size: "xsmall"
13081
- }) : prefix), /*#__PURE__*/React__default["default"].createElement(StyledLabelContainerInsideTextInput, {
13144
+ }, renderPrefix({
13145
+ state: state,
13146
+ prefix: prefix
13147
+ })), /*#__PURE__*/React__default["default"].createElement(StyledLabelContainerInsideTextInput, {
13082
13148
  themeVariant: variant,
13083
13149
  pointerEvents: "none",
13084
13150
  style: [{
@@ -13115,28 +13181,26 @@ var TextInput = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
13115
13181
  testID: "input-label",
13116
13182
  themeState: state,
13117
13183
  onLayout: onLabelLayout
13118
- }, label)), /*#__PURE__*/React__default["default"].createElement(StyledTextInputAndLabelContainer, null, renderInputValue ? renderInputValue(nativeInputProps) : /*#__PURE__*/React__default["default"].createElement(StyledTextInput, _extends$1({}, nativeInputProps, {
13119
- themeVariant: variant,
13120
- multiline: variant === 'textarea' || nativeProps.multiline,
13121
- ref: function ref(reference) {
13122
- innerTextInput.current = reference;
13184
+ }, label)), /*#__PURE__*/React__default["default"].createElement(StyledTextInputAndLabelContainer, null, renderInput({
13185
+ variant: variant,
13186
+ nativeInputProps: nativeInputProps,
13187
+ renderInputValue: renderInputValue,
13188
+ ref: function ref(rnTextInputRef) {
13189
+ innerTextInput.current = rnTextInputRef;
13123
13190
  }
13124
- }))), typeof actualSuffix === 'string' ? /*#__PURE__*/React__default["default"].createElement(Icon, {
13125
- intent: state === 'disabled' ? 'disabled-text' : 'text',
13126
- testID: "input-suffix",
13127
- icon: actualSuffix,
13128
- spin: actualSuffix === 'loading',
13129
- size: "medium"
13130
- }) : suffix), /*#__PURE__*/React__default["default"].createElement(StyledErrorAndHelpTextContainer, null, /*#__PURE__*/React__default["default"].createElement(StyledErrorAndMaxLengthContainer, null, error ? /*#__PURE__*/React__default["default"].createElement(StyledErrorContainer$2, null, /*#__PURE__*/React__default["default"].createElement(Icon, {
13131
- testID: "input-error-icon",
13132
- icon: "circle-info",
13133
- size: "xsmall",
13134
- intent: "danger"
13135
- }), /*#__PURE__*/React__default["default"].createElement(StyledError, {
13136
- testID: "input-error-message"
13137
- }, error)) : !!helpText && /*#__PURE__*/React__default["default"].createElement(StyledHelperText, null, helpText), shouldShowMaxLength && /*#__PURE__*/React__default["default"].createElement(StyledMaxLengthMessage, {
13138
- themeState: state
13139
- }, displayText.length, "/", maxLength))));
13191
+ })), renderSuffix({
13192
+ state: state,
13193
+ loading: loading,
13194
+ suffix: suffix
13195
+ })), /*#__PURE__*/React__default["default"].createElement(StyledErrorAndHelpTextContainer, null, /*#__PURE__*/React__default["default"].createElement(StyledErrorAndMaxLengthContainer, null, renderErrorOrHelpText({
13196
+ error: error,
13197
+ helpText: helpText
13198
+ }), renderMaxLengthMessage({
13199
+ state: state,
13200
+ currentLength: displayText.length,
13201
+ maxLength: maxLength,
13202
+ hideCharacterCount: hideCharacterCount
13203
+ }))));
13140
13204
  });
13141
13205
 
13142
13206
  var getDateValue = function getDateValue(value, minDate, maxDate) {
@@ -14821,13 +14885,30 @@ var CTAWrapper = index$9(reactNative.TouchableOpacity)(function (_ref6) {
14821
14885
  };
14822
14886
  });
14823
14887
 
14824
- var ToastContext = /*#__PURE__*/React.createContext({});
14888
+ var fallbackToastControlContext = {
14889
+ show: function show(_) {
14890
+ return '';
14891
+ },
14892
+ hide: function hide(_) {
14893
+ // Fallback empty function
14894
+ },
14895
+ clearAll: function clearAll() {
14896
+ // Fallback empty function
14897
+ }
14898
+ };
14899
+ var ToastContext = /*#__PURE__*/React.createContext(fallbackToastControlContext);
14825
14900
  var ToastConfigContext = /*#__PURE__*/React.createContext({});
14826
14901
  var useToastConfig = function useToastConfig() {
14827
14902
  return React.useContext(ToastConfigContext);
14828
14903
  };
14829
14904
  var useToast = function useToast() {
14830
- return React.useContext(ToastContext);
14905
+ var context = React.useContext(ToastContext);
14906
+ if (!context) {
14907
+ // eslint-disable-next-line no-console
14908
+ console.warn('Toast was used without ToastProvider');
14909
+ return fallbackToastControlContext;
14910
+ }
14911
+ return context;
14831
14912
  };
14832
14913
 
14833
14914
  var getIntentIcon = function getIntentIcon(intent) {
@@ -15026,8 +15107,7 @@ var ToastProvider = function ToastProvider(_ref) {
15026
15107
  var position = _position === undefined ? 'bottom' : _position;
15027
15108
  useDeprecation("Toast's position prop is deprecated and will be removed in the next major release.\nPlease remove it.", _position !== undefined);
15028
15109
  var toastRef = React.useRef(null);
15029
- // @ts-expect-error: TODO: @tungv Fix this type error
15030
- var _useState = React.useState(null),
15110
+ var _useState = React.useState(),
15031
15111
  _useState2 = _slicedToArray(_useState, 2),
15032
15112
  refState = _useState2[0],
15033
15113
  setRefState = _useState2[1];
@@ -15043,7 +15123,7 @@ var ToastProvider = function ToastProvider(_ref) {
15043
15123
  };
15044
15124
  }, [displayType, position]);
15045
15125
  return /*#__PURE__*/React__default["default"].createElement(ToastContext.Provider, {
15046
- value: refState
15126
+ value: refState || fallbackToastControlContext
15047
15127
  }, /*#__PURE__*/React__default["default"].createElement(reactNative.View, {
15048
15128
  style: {
15049
15129
  flex: 1
@@ -17611,18 +17691,16 @@ var ScrollableTabHeader = function ScrollableTabHeader(_ref2) {
17611
17691
  });
17612
17692
  }, 100);
17613
17693
  },
17614
- style:
17615
- // Border styles specified in contentContainerStyle don't work
17616
- // so they need to be placed here instead on Android.
17617
- reactNative.Platform.OS === 'android' ? {
17694
+ style: {
17618
17695
  borderBottomColor: theme.__hd__.tabs.colors.headerBottom,
17619
17696
  borderBottomWidth: theme.__hd__.tabs.sizes.indicator
17620
- } : undefined,
17621
- contentContainerStyle: {
17622
- paddingHorizontal: theme.__hd__.tabs.space.flatListHorizontalPadding,
17697
+ },
17698
+ contentContainerStyle: _objectSpread2({
17699
+ paddingHorizontal: theme.__hd__.tabs.space.flatListHorizontalPadding
17700
+ }, reactNative.Platform.OS === 'android' && {
17623
17701
  borderBottomColor: theme.__hd__.tabs.colors.headerBottom,
17624
17702
  borderBottomWidth: theme.__hd__.tabs.sizes.indicator
17625
- },
17703
+ }),
17626
17704
  renderItem: function renderItem(_ref4) {
17627
17705
  var tab = _ref4.item,
17628
17706
  index = _ref4.index;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hero-design/rn",
3
- "version": "8.57.0",
3
+ "version": "8.58.0",
4
4
  "license": "MIT",
5
5
  "main": "lib/index.js",
6
6
  "module": "es/index.js",
@@ -24,13 +24,12 @@
24
24
  "@emotion/react": "^11.9.3",
25
25
  "@hero-design/colors": "8.42.5",
26
26
  "date-fns": "^2.16.1",
27
- "events": "^3.2.0",
28
27
  "hero-editor": "^1.9.21",
29
28
  "nanoid": "^4.0.2"
30
29
  },
31
30
  "peerDependencies": {
32
- "@hero-design/react-native-month-year-picker": "^8.42.6",
33
- "@react-native-community/datetimepicker": "^3.5.2",
31
+ "@hero-design/react-native-month-year-picker": "^8.42.7",
32
+ "@react-native-community/datetimepicker": "^3.5.2 || ^7.2.0",
34
33
  "@react-native-community/slider": "4.4.3",
35
34
  "react": "18.2.0",
36
35
  "react-native": "^0.71.0",
@@ -49,8 +48,8 @@
49
48
  "@babel/runtime": "^7.20.0",
50
49
  "@emotion/jest": "^11.11.0",
51
50
  "@hero-design/eslint-plugin": "9.0.0",
52
- "@hero-design/react-native-month-year-picker": "^8.42.6",
53
- "@react-native-community/datetimepicker": "3.5.2",
51
+ "@hero-design/react-native-month-year-picker": "^8.42.7",
52
+ "@react-native-community/datetimepicker": "7.2.0",
54
53
  "@react-native-community/slider": "4.4.3",
55
54
  "@rollup/plugin-babel": "^5.3.1",
56
55
  "@rollup/plugin-commonjs": "^21.0.1",
@@ -60,6 +59,7 @@
60
59
  "@rollup/plugin-typescript": "^8.3.0",
61
60
  "@testing-library/jest-native": "^5.4.2",
62
61
  "@testing-library/react-native": "^9.1.0",
62
+ "@types/events": "^3.0.3",
63
63
  "@types/jest": "^29.5.3",
64
64
  "@types/react": "^18.2.0",
65
65
  "@types/react-native-vector-icons": "^6.4.10",
@@ -114,9 +114,9 @@ describe('Calendar', () => {
114
114
  platform
115
115
  ${'ios'}
116
116
  ${'android'}
117
- `('renders correct picker on $platform', ({ platform }) => {
117
+ `('renders correct picker on $platform', ({ platform: mockedPlatform }) => {
118
118
  jest.mock('react-native/Libraries/Utilities/Platform', () => ({
119
- OS: platform,
119
+ OS: mockedPlatform,
120
120
  select: () => null,
121
121
  }));
122
122
 
@@ -133,7 +133,7 @@ describe('Calendar', () => {
133
133
  fireEvent.press(getByTestId('calendar-month-picker'));
134
134
 
135
135
  // Pickers are mocked at packages/rn/testUtils/setup.tsx
136
- if (platform === 'ios') {
136
+ if (mockedPlatform === 'ios') {
137
137
  expect(queryByText('IOS picker')).toBeDefined();
138
138
  } else {
139
139
  expect(queryByText('Android picker')).toBeDefined();
@@ -146,9 +146,9 @@ describe('Calendar', () => {
146
146
  ${'android'}
147
147
  `(
148
148
  'onToggleMonthPicker is called when toggling month year picker on $platform',
149
- ({ platform }) => {
149
+ ({ platform: mockedPlatform }) => {
150
150
  jest.mock('react-native/Libraries/Utilities/Platform', () => ({
151
- OS: platform,
151
+ OS: mockedPlatform,
152
152
  select: () => null,
153
153
  }));
154
154
 
@@ -67,6 +67,10 @@ export interface CardCarouselProps {
67
67
  onLayout?: (event: LayoutChangeEvent) => void;
68
68
  }
69
69
 
70
+ export const getCardCarouselValidIndex = (index: number, length: number) => {
71
+ return Math.min(Math.max(index, 0), length - 1);
72
+ };
73
+
70
74
  export const CardCarousel = forwardRef<CardCarouselHandles, CardCarouselProps>(
71
75
  (
72
76
  {
@@ -92,13 +96,7 @@ export const CardCarousel = forwardRef<CardCarouselHandles, CardCarouselProps>(
92
96
  Platform.OS === 'ios' ? VIEW_POSITION_CENTER : undefined;
93
97
  const snapToIndex = useCallback(
94
98
  (index: number) => {
95
- let validIndex = 0;
96
-
97
- if (index >= items.length) {
98
- validIndex = items.length - 1;
99
- } else if (index >= 0) {
100
- validIndex = index;
101
- }
99
+ const validIndex = getCardCarouselValidIndex(index, items.length);
102
100
 
103
101
  carouselRef.current?.scrollToIndex({
104
102
  index: validIndex,
@@ -106,7 +104,7 @@ export const CardCarousel = forwardRef<CardCarouselHandles, CardCarouselProps>(
106
104
  viewPosition,
107
105
  });
108
106
  },
109
- [carouselRef, itemWidth]
107
+ [items.length, viewPosition]
110
108
  );
111
109
 
112
110
  /*
@@ -122,7 +120,7 @@ export const CardCarousel = forwardRef<CardCarouselHandles, CardCarouselProps>(
122
120
  animated: true,
123
121
  viewPosition,
124
122
  });
125
- }, [carouselRef, currentIndex, itemWidth, items.length]);
123
+ }, [currentIndex, items.length, viewPosition]);
126
124
 
127
125
  React.useImperativeHandle(
128
126
  ref,
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { useTheme } from '@emotion/react';
2
3
  import {
3
4
  StyledCarouselContentWrapper,
4
5
  StyledCarouselHeading,
@@ -26,27 +27,38 @@ const CarouselItem = ({
26
27
  heading,
27
28
  body,
28
29
  }: CarouselItemProps) => {
29
- return (
30
- <Box style={{ width }}>
31
- {image &&
32
- (isCarouselImageProps(image) ? (
30
+ const theme = useTheme();
31
+
32
+ const ImageComponent = React.useMemo(() => {
33
+ if (image) {
34
+ if (isCarouselImageProps(image)) {
35
+ return (
33
36
  <StyledCustomSizeCarouselImage
34
37
  source={image}
35
38
  height={image.height}
36
39
  width={image.width}
37
40
  resizeMode={image.resizeMode}
41
+ style={{ marginBottom: theme.space.medium }}
38
42
  />
39
- ) : (
40
- <StyledCarouselImage
41
- source={typeof image === 'string' ? { uri: image } : image}
42
- />
43
- ))}
43
+ );
44
+ }
45
+
46
+ return (
47
+ <StyledCarouselImage
48
+ source={typeof image === 'string' ? { uri: image } : image}
49
+ style={{ marginBottom: theme.space.medium }}
50
+ />
51
+ );
52
+ }
53
+
54
+ return null;
55
+ }, [image]);
56
+
57
+ return (
58
+ <Box style={{ width }}>
59
+ {ImageComponent}
44
60
 
45
- <StyledCarouselContentWrapper
46
- paddingHorizontal="large"
47
- marginTop="large"
48
- width={width}
49
- >
61
+ <StyledCarouselContentWrapper paddingHorizontal="medium" width={width}>
50
62
  {content}
51
63
  <StyledCarouselHeading level="h1" typeface="playful">
52
64
  {heading}
@@ -22,7 +22,6 @@ const StyledCarouselView = styled(View)(() => ({
22
22
  }));
23
23
 
24
24
  const StyledCarouselHeading = styled(Typography.Title)(({ theme }) => ({
25
- marginTop: theme.__hd__.carousel.space.headingMarginTop,
26
25
  marginBottom: theme.__hd__.carousel.space.headingMarginBottom,
27
26
  }));
28
27
 
@@ -34,8 +33,8 @@ const StyledCarouselImage = styled(Image)(() => ({
34
33
  }));
35
34
 
36
35
  const StyledCustomSizeCarouselImage = styled(Image)<{
37
- height?: number;
38
- width?: number;
36
+ height?: number | `${number}%`;
37
+ width?: number | `${number}%`;
39
38
  resizeMode?: ImageResizeMode;
40
39
  }>(({ height, resizeMode = 'contain', width }) => ({
41
40
  alignSelf: 'center',