diff --git a/package.json b/package.json index 75792534d..07ba6f971 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "husky": "^8.0.3", "identity-obj-proxy": "^3.0.0", "image-js": "^0.35.6", + "jest": "^29.4.1", "lint-staged": "^10.5.4", "mendix-client": "^7.15.8", "patch-package": "^8.0.0", @@ -79,6 +80,7 @@ "react-dom": "18.3.1", "recursive-copy": "^2.0.14", "rollup": "^2.79.2", + "ts-jest": "^29.4.0", "ts-node": "^10.9.2" }, "commitlint": { diff --git a/packages/pluggableWidgets/intro-screen-native/CHANGELOG.md b/packages/pluggableWidgets/intro-screen-native/CHANGELOG.md index fd233833f..cec203289 100644 --- a/packages/pluggableWidgets/intro-screen-native/CHANGELOG.md +++ b/packages/pluggableWidgets/intro-screen-native/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Fixed - We have fixed defaultProps deprecation warning. +- Initial slide now correctly positioned on mount. ## [4.0.0] - 2024-12-3 diff --git a/packages/pluggableWidgets/intro-screen-native/package.json b/packages/pluggableWidgets/intro-screen-native/package.json index 04509a5da..a6dc423c8 100644 --- a/packages/pluggableWidgets/intro-screen-native/package.json +++ b/packages/pluggableWidgets/intro-screen-native/package.json @@ -1,7 +1,7 @@ { "name": "intro-screen-native", "widgetName": "IntroScreen", - "version": "4.0.1", + "version": "4.1.0", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/pluggableWidgets/intro-screen-native/src/IntroScreen.tsx b/packages/pluggableWidgets/intro-screen-native/src/IntroScreen.tsx index 997fedaa5..f9dfd7de1 100644 --- a/packages/pluggableWidgets/intro-screen-native/src/IntroScreen.tsx +++ b/packages/pluggableWidgets/intro-screen-native/src/IntroScreen.tsx @@ -24,19 +24,27 @@ export function IntroScreen(props: IntroScreenProps): JSX.Elem } else { setVisible(true); } - }, []); + }, [props.identifier]); + + const hideModal = useCallback((): void => { + if (props.identifier) { + AsyncStorage.setItem(props.identifier, "gone").then(() => setVisible(false)); + } else { + setVisible(false); + } + }, [props.identifier]); const onDone = useCallback(() => { hideModal(); executeAction(props.onDone); - }, [props.onDone]); + }, [hideModal, props.onDone]); const onSlideChange = useCallback(() => executeAction(props.onSlideChange), [props.onSlideChange]); const onSkip = useCallback(() => { hideModal(); executeAction(props.onSkip); - }, [props.onSkip]); + }, [hideModal, props.onSkip]); const checkLabel = (label?: DynamicValue): string | undefined => { if (label && label.value && label.status === ValueStatus.Available) { @@ -45,14 +53,6 @@ export function IntroScreen(props: IntroScreenProps): JSX.Elem return undefined; }; - const hideModal = (): void => { - if (props.identifier) { - AsyncStorage.setItem(props.identifier, "gone").then(() => setVisible(false)); - } else { - setVisible(false); - } - }; - const showSkipPrevious = props.buttonPattern === "all"; const showNextDone = props.buttonPattern !== "none"; diff --git a/packages/pluggableWidgets/intro-screen-native/src/SwipeableContainer.tsx b/packages/pluggableWidgets/intro-screen-native/src/SwipeableContainer.tsx index 78950e20c..3a9184e19 100644 --- a/packages/pluggableWidgets/intro-screen-native/src/SwipeableContainer.tsx +++ b/packages/pluggableWidgets/intro-screen-native/src/SwipeableContainer.tsx @@ -8,7 +8,9 @@ import { StyleSheet, Text, TouchableNativeFeedback, + TouchableNativeFeedbackProps, TouchableOpacity, + TouchableOpacityProps, View } from "react-native"; import { ButtonStyle, IntroScreenStyle } from "./ui/Styles"; @@ -43,10 +45,13 @@ interface SwipeableContainerProps { activeSlide?: EditableValue; } +type TouchableProps = TouchableNativeFeedbackProps | TouchableOpacityProps; + declare type Option = T | undefined; const isAndroidRTL = I18nManager.isRTL && Platform.OS === "android"; -const Touchable = Platform.OS === "android" ? TouchableNativeFeedback : TouchableOpacity; +const Touchable: React.ComponentType = + Platform.OS === "android" ? TouchableNativeFeedback : TouchableOpacity; const refreshActiveSlideAttribute = (slides: SlidesType[], activeSlide?: EditableValue): number => { if (activeSlide && activeSlide.status === ValueStatus.Available && slides && slides.length > 0) { @@ -66,12 +71,10 @@ export const SwipeableContainer = (props: SwipeableContainerProps): ReactElement const [activeIndex, setActiveIndex] = useState(0); const flatList = useRef>(null); - useEffect(() => { - const slide = refreshActiveSlideAttribute(props.slides, props.activeSlide); - if (width && props.activeSlide && props.activeSlide.status === ValueStatus.Available && slide !== activeIndex) { - goToSlide(slide); - } - }, [props.activeSlide, activeIndex, width]); + const rtlSafeIndex = useCallback( + (i: number): number => (isAndroidRTL ? props.slides.length - 1 - i : i), + [props.slides.length] + ); const goToSlide = useCallback( (pageNum: number) => { @@ -82,9 +85,16 @@ export const SwipeableContainer = (props: SwipeableContainerProps): ReactElement }); } }, - [width, flatList] + [rtlSafeIndex, width] ); + useEffect(() => { + const slide = refreshActiveSlideAttribute(props.slides, props.activeSlide); + if (width && props.activeSlide?.status === ValueStatus.Available && slide !== activeIndex) { + goToSlide(slide); + } + }, [props.activeSlide, activeIndex, width, props.slides, goToSlide]); + const onNextPress = (): void => { goToSlide(activeIndex + 1); onSlideChange(activeIndex + 1, activeIndex); @@ -278,11 +288,6 @@ export const SwipeableContainer = (props: SwipeableContainerProps): ReactElement ); }; - const rtlSafeIndex = useCallback( - (i: number): number => (isAndroidRTL ? props.slides.length - 1 - i : i), - [props.slides.length] - ); - const onMomentumScrollEnd = useCallback( (event: NativeSyntheticEvent) => { const offset = event.nativeEvent.contentOffset.x; @@ -314,6 +319,8 @@ export const SwipeableContainer = (props: SwipeableContainerProps): ReactElement ({ length: width, offset: width * i, index: i })} ref={flatList} data={props.slides} horizontal diff --git a/packages/pluggableWidgets/intro-screen-native/src/__tests__/__snapshots__/IntroScreen.notch.spec.tsx.snap b/packages/pluggableWidgets/intro-screen-native/src/__tests__/__snapshots__/IntroScreen.notch.spec.tsx.snap index e2a9e26d2..804124a9d 100644 --- a/packages/pluggableWidgets/intro-screen-native/src/__tests__/__snapshots__/IntroScreen.notch.spec.tsx.snap +++ b/packages/pluggableWidgets/intro-screen-native/src/__tests__/__snapshots__/IntroScreen.notch.spec.tsx.snap @@ -37,7 +37,9 @@ exports[`Intro Screen renders 1`] = ` extraData={0} getItem={[Function]} getItemCount={[Function]} + getItemLayout={[Function]} horizontal={true} + initialScrollIndex={0} keyExtractor={[Function]} onContentSizeChange={[Function]} onLayout={[Function]} @@ -64,7 +66,6 @@ exports[`Intro Screen renders 1`] = ` - + diff --git a/yarn.lock b/yarn.lock index 266322625..13aba7fbe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12310,6 +12310,7 @@ __metadata: husky: "npm:^8.0.3" identity-obj-proxy: "npm:^3.0.0" image-js: "npm:^0.35.6" + jest: "npm:^29.4.1" lint-staged: "npm:^10.5.4" mendix-client: "npm:^7.15.8" patch-package: "npm:^8.0.0" @@ -12320,6 +12321,7 @@ __metadata: react-dom: "npm:18.3.1" recursive-copy: "npm:^2.0.14" rollup: "npm:^2.79.2" + ts-jest: "npm:^29.4.0" ts-node: "npm:^10.9.2" languageName: unknown linkType: soft @@ -15502,6 +15504,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.7.2": + version: 7.7.2 + resolution: "semver@npm:7.7.2" + bin: + semver: bin/semver.js + checksum: 10/7a24cffcaa13f53c09ce55e05efe25cd41328730b2308678624f8b9f5fc3093fc4d189f47950f0b811ff8f3c3039c24a2c36717ba7961615c682045bf03e1dda + languageName: node + linkType: hard + "send@npm:0.19.0": version: 0.19.0 resolution: "send@npm:0.19.0" @@ -16690,6 +16701,46 @@ __metadata: languageName: node linkType: hard +"ts-jest@npm:^29.4.0": + version: 29.4.0 + resolution: "ts-jest@npm:29.4.0" + dependencies: + bs-logger: "npm:^0.2.6" + ejs: "npm:^3.1.10" + fast-json-stable-stringify: "npm:^2.1.0" + json5: "npm:^2.2.3" + lodash.memoize: "npm:^4.1.2" + make-error: "npm:^1.3.6" + semver: "npm:^7.7.2" + type-fest: "npm:^4.41.0" + yargs-parser: "npm:^21.1.1" + peerDependencies: + "@babel/core": ">=7.0.0-beta.0 <8" + "@jest/transform": ^29.0.0 || ^30.0.0 + "@jest/types": ^29.0.0 || ^30.0.0 + babel-jest: ^29.0.0 || ^30.0.0 + jest: ^29.0.0 || ^30.0.0 + jest-util: ^29.0.0 || ^30.0.0 + typescript: ">=4.3 <6" + peerDependenciesMeta: + "@babel/core": + optional: true + "@jest/transform": + optional: true + "@jest/types": + optional: true + babel-jest: + optional: true + esbuild: + optional: true + jest-util: + optional: true + bin: + ts-jest: cli.js + checksum: 10/fe501f3d9946ec52db78ae0ac6cfd72942b1c1f5d657c12db321c9d570f0f499e83eb6c7e26074cd11dfe534a6a09c676947e7a63ee08fcda552aabcdeb6c592 + languageName: node + linkType: hard + "ts-node@npm:^10.9.1, ts-node@npm:^10.9.2": version: 10.9.2 resolution: "ts-node@npm:10.9.2" @@ -16867,6 +16918,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^4.41.0": + version: 4.41.0 + resolution: "type-fest@npm:4.41.0" + checksum: 10/617ace794ac0893c2986912d28b3065ad1afb484cad59297835a0807dc63286c39e8675d65f7de08fafa339afcb8fe06a36e9a188b9857756ae1e92ee8bda212 + languageName: node + linkType: hard + "typed-array-buffer@npm:^1.0.3": version: 1.0.3 resolution: "typed-array-buffer@npm:1.0.3"