Skip to content

Commit

Permalink
Merge branch 'patch/v1.10.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
troberts-28 committed Jul 30, 2024
2 parents fe52432 + b266929 commit dd5168d
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 62 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Includes iOS-style haptic and audio feedback 🍏
- [Props 💅](#props-)
- [TimerPicker ⏲️](#timerpicker-️)
- [Custom Styles 👗](#custom-styles-)
- [Performance](#performance)
- [Custom FlatList](#custom-flatlist)
- [TimerPickerModal ⏰](#timerpickermodal-)
- [Custom Styles 👕](#custom-styles--1)
Expand Down Expand Up @@ -448,6 +449,9 @@ return (
| use12HourPicker | Switch the hour picker to 12-hour format with an AM / PM label | Boolean | false | false |
| amLabel | Set the AM label if using the 12-hour picker | String | am | false |
| pmLabel | Set the PM label if using the 12-hour picker | String | pm | false |
| repeatHourNumbersNTimes | Set the number of times the list of hours is repeated in the picker | Number | 6 | false |
| repeatMinuteNumbersNTimes | Set the number of times the list of minutes is repeated in the picker | Number | 3 | false |
| repeatSecondNumbersNTimes | Set the number of times the list of seconds is repeated in the picker | Number | 3 | false |
| disableInfiniteScroll | Disable the infinite scroll feature | Boolean | false | false |
| LinearGradient | Linear Gradient Component | [expo-linear-gradient](https://www.npmjs.com/package/expo-linear-gradient).LinearGradient or [react-native-linear-gradient](https://www.npmjs.com/package/react-native-linear-gradient).default | - | false |
| Haptics | Haptics Namespace (required for Haptic feedback) | [expo-haptics](https://www.npmjs.com/package/expo-haptics) | - | false |
Expand Down Expand Up @@ -483,6 +487,15 @@ The following custom styles can be supplied to re-style the component in any way
Note the minor limitations to the allowed styles for `pickerContainer` and `pickerItemContainer`. These are made because these styles are used for internal calculations and all possible `backgroundColor`/`height` types are not supported.


#### Performance

When the `disableInfiniteScroll` prop is not set, the picker gives the appearance of an infinitely scrolling picker by auto-scrolling forward/back when you near the start/end of the list. When the picker auto-scrolls, a momentary flicker is visible if you are scrolling very slowly.

To mitigate for this, you can modify the `repeatHourNumbersNTimes`, `repeatMinuteNumbersNTimes` and `repeatSecondNumbersNTimes` props. These set the number of times the list of numbers in each picker is repeated. These have a performance trade-off: higher values mean the picker has to auto-scroll less to maintain the infinite scroll, but has to render a longer list of numbers. By default, the props are set to 6, 3 and 3, respectively, which balances that trade-off effectively.

Note that you can avoid the auto-scroll flickering entirely by disabling infinite scroll. You could then set the above props to high values, so that a user has to scroll far down/up the list to reach the end of the list.


#### Custom FlatList

The library offers the ability to provide a custom component for the `<FlatList />`, instead of the default React Native component. This allows for more flexibility and integration with libraries like [react-native-gesture-handler](react-native-gesture-handler) or other components built on top of it, like [https://ui.gorhom.dev/components/bottom-sheet](https://ui.gorhom.dev/components/bottom-sheet).
Expand Down
4 changes: 4 additions & 0 deletions example/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export default function App() {
<TimerPickerModal
Audio={Audio}
closeOnOverlayPress
disableInfiniteScroll
Haptics={Haptics}
LinearGradient={LinearGradient}
modalProps={{
Expand All @@ -118,6 +119,9 @@ export default function App() {
setAlarmStringExample1(formatTime(pickedDuration));
setShowPickerExample1(false);
}}
repeatHourNumbersNTimes={1}
repeatMinuteNumbersNTimes={1}
repeatSecondNumbersNTimes={1}
setIsVisible={setShowPickerExample1}
styles={{
theme: "dark",
Expand Down
2 changes: 1 addition & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"dependencies": {
"@expo/vector-icons": "^14.0.0",
"expo": "~51.0.20",
"expo": "~51.0.23",
"expo-av": "~14.0.5",
"expo-haptics": "~13.0.1",
"expo-linear-gradient": "~13.0.2",
Expand Down
66 changes: 45 additions & 21 deletions example/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -852,10 +852,10 @@
mv "~2"
safe-json-stringify "~1"

"@expo/[email protected].25":
version "0.18.25"
resolved "https://registry.yarnpkg.com/@expo/cli/-/cli-0.18.25.tgz#92f710a028db8f133fede556c129e74d9263faca"
integrity sha512-Kh0uZGCxwu58Pu7Jto9T/ABlBR7nkx8QC0Wv8pI3YtISyQZIKtbtNNeTPWYbVK1ddswKwtBUj+MNhKoDL49TLg==
"@expo/[email protected].26":
version "0.18.26"
resolved "https://registry.yarnpkg.com/@expo/cli/-/cli-0.18.26.tgz#56e60eaae12b82a8aeb33f2050bbfb6683f87187"
integrity sha512-u9bTTXgcjaTloE9CHwxgrb8Me/Al4jiPykbVQpJydakH3GsIZfHy1zaLc7O39CoLjRz37WWi6Y5ZdgtQw9dCPQ==
dependencies:
"@babel/runtime" "^7.20.0"
"@expo/code-signing-certificates" "0.0.5"
Expand Down Expand Up @@ -1041,7 +1041,31 @@
json5 "^2.2.2"
write-file-atomic "^2.3.0"

"@expo/[email protected]", "@expo/metro-config@~0.18.6":
"@expo/[email protected]":
version "0.18.10"
resolved "https://registry.yarnpkg.com/@expo/metro-config/-/metro-config-0.18.10.tgz#2b0ec353c38802dd89028432c3a463804df94f24"
integrity sha512-HTYQqKfV0JSuRp5aDvrPHezj5udXOWoXqHOjfTSnce2m13j6D0yYXTJNaKRhlgpPBrkg5DL7z1fL3zwDUpLM4w==
dependencies:
"@babel/core" "^7.20.0"
"@babel/generator" "^7.20.5"
"@babel/parser" "^7.20.0"
"@babel/types" "^7.20.0"
"@expo/config" "~9.0.0-beta.0"
"@expo/env" "~0.3.0"
"@expo/json-file" "~8.3.0"
"@expo/spawn-async" "^1.7.2"
chalk "^4.1.0"
debug "^4.3.2"
find-yarn-workspace-root "~2.0.0"
fs-extra "^9.1.0"
getenv "^1.0.0"
glob "^7.2.3"
jsc-safe-url "^0.2.4"
lightningcss "~1.19.0"
postcss "~8.4.32"
resolve-from "^5.0.0"

"@expo/metro-config@~0.18.6":
version "0.18.8"
resolved "https://registry.yarnpkg.com/@expo/metro-config/-/metro-config-0.18.8.tgz#2902bfdb864876da3cf5b1822a554bbb011e4a77"
integrity sha512-YGpTlVc1/6EPzPbt0LZt92Bwrpjngulup6uHSTRbwn/heMPfFaVv1Y4VE3GAUkx7/Qwu+dTVIV0Kys4pLOAIiw==
Expand Down Expand Up @@ -3349,10 +3373,10 @@ expo-file-system@~17.0.1:
resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-17.0.1.tgz#b9f8af8c1c06ec71d96fd7a0d2567fa9e1c88f15"
integrity sha512-dYpnZJqTGj6HCYJyXAgpFkQWsiCH3HY1ek2cFZVHFoEc5tLz9gmdEgTF6nFHurvmvfmXqxi7a5CXyVm0aFYJBw==

expo-font@~12.0.8:
version "12.0.8"
resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-12.0.8.tgz#23b769063ba72484c767a4fdb0ff3a26d23645d2"
integrity sha512-xK9kOEyD/vnREicM5yS2uVwzB83weu+UE6QwJRH2dhoQcdJiWGGKOj+blJ8GrtU+BqtyNijyWcwfBbYOJnf8eQ==
expo-font@~12.0.9:
version "12.0.9"
resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-12.0.9.tgz#096860a6b8b5dd54152262eafd318593ec2db48c"
integrity sha512-seTCyf0tbgkAnp3ZI9ZfK9QVtURQUgFnuj+GuJ5TSnN0XsOtVe1s2RxTvmMgkfuvfkzcjJ69gyRpsZS1cC8hjw==
dependencies:
fontfaceobserver "^2.1.0"

Expand Down Expand Up @@ -3382,31 +3406,31 @@ [email protected]:
find-up "^5.0.0"
fs-extra "^9.1.0"

[email protected].19:
version "1.12.19"
resolved "https://registry.yarnpkg.com/expo-modules-core/-/expo-modules-core-1.12.19.tgz#3212df74206ce29d85a4aed0612f6b9d4d967105"
integrity sha512-fFsErN4oMsOdStUVYvyLpl6MX/wbD9yJSqy/Lu7ZRLIPzeKDfGS2jNl8RzryPznRpWmy49X8l40R4osRJLizhg==
[email protected].20:
version "1.12.20"
resolved "https://registry.yarnpkg.com/expo-modules-core/-/expo-modules-core-1.12.20.tgz#072dea10791f32ea5d1d3b15a7d5fd1984173429"
integrity sha512-CCXjlgT8lDAufgt912P1W7TwD+KAylfIttc1Doh1a0hAfkdkUsDRmrgthnYrrxEo2ECVpbaB71Epp1bnZ1rRrA==
dependencies:
invariant "^2.2.4"

expo@~51.0.20:
version "51.0.20"
resolved "https://registry.yarnpkg.com/expo/-/expo-51.0.20.tgz#e34ce895875e29bb46a818ff5be7178b4fce2bfb"
integrity sha512-EmNZel6j7pU4YF1QcIcgpVdYsA1lASQcEw9PPSevjreNT6nlge2CNHB6mAphAKGz5PdgcWYBn/v4qQj1/FJuZQ==
expo@~51.0.23:
version "51.0.23"
resolved "https://registry.yarnpkg.com/expo/-/expo-51.0.23.tgz#a2813c4ea45f5158838221093a6a08eae47534a1"
integrity sha512-tZv7hiDIlKMlQxzC/IxfiLEpp0xcm6VISuoeFobkvoelEWsj6bpjlsF0HP4k6pr3ELL++r7wE1VGYa/AceC6+w==
dependencies:
"@babel/runtime" "^7.20.0"
"@expo/cli" "0.18.25"
"@expo/cli" "0.18.26"
"@expo/config" "9.0.3"
"@expo/config-plugins" "8.0.8"
"@expo/metro-config" "0.18.8"
"@expo/metro-config" "0.18.10"
"@expo/vector-icons" "^14.0.0"
babel-preset-expo "~11.0.12"
expo-asset "~10.0.10"
expo-file-system "~17.0.1"
expo-font "~12.0.8"
expo-font "~12.0.9"
expo-keep-awake "~13.0.2"
expo-modules-autolinking "1.11.1"
expo-modules-core "1.12.19"
expo-modules-core "1.12.20"
fbemitter "^3.0.0"
whatwg-url-without-unicode "8.0.0-3"

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"url": "https://github.com/troberts-28"
},
"license": "MIT",
"version": "1.10.1",
"version": "1.10.2",
"main": "dist/commonjs/index.js",
"module": "dist/module/index.js",
"types": "dist/typescript/index.d.ts",
Expand Down
92 changes: 63 additions & 29 deletions src/components/DurationScroll/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React, {
useImperativeHandle,
useState,
useEffect,
useMemo,
} from "react";

import { View, Text, FlatList as RNFlatList } from "react-native";
Expand Down Expand Up @@ -49,35 +50,59 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
padWithNItems,
pickerGradientOverlayProps,
pmLabel,
repeatNumbersNTimes = 3,
styles,
testID,
topPickerGradientOverlayProps,
} = props;

const data = !is12HourPicker
? generateNumbers(numberOfItems, {
padNumbersWithZero,
repeatNTimes: 3,
disableInfiniteScroll,
padWithNItems,
})
: generate12HourNumbers({
padNumbersWithZero,
repeatNTimes: 3,
disableInfiniteScroll,
padWithNItems,
});

const numberOfItemsToShow = 1 + padWithNItems * 2;

const adjustedLimited = getAdjustedLimit(limit, numberOfItems);
const data = useMemo(() => {
if (is12HourPicker) {
return generate12HourNumbers({
padNumbersWithZero,
repeatNTimes: repeatNumbersNTimes,
disableInfiniteScroll,
padWithNItems,
});
}

const initialScrollIndex = getScrollIndex({
value: initialValue,
return generateNumbers(numberOfItems, {
padNumbersWithZero,
repeatNTimes: repeatNumbersNTimes,
disableInfiniteScroll,
padWithNItems,
});
}, [
disableInfiniteScroll,
is12HourPicker,
numberOfItems,
padNumbersWithZero,
padWithNItems,
disableInfiniteScroll,
});
repeatNumbersNTimes,
]);

const initialScrollIndex = useMemo(
() =>
getScrollIndex({
numberOfItems,
padWithNItems,
repeatNumbersNTimes,
value: initialValue,
}),
[
initialValue,
numberOfItems,
padWithNItems,
repeatNumbersNTimes,
]
);

const adjustedLimited = useMemo(
() => getAdjustedLimit(limit, numberOfItems),
[limit, numberOfItems]
);

const numberOfItemsToShow = 1 + padWithNItems * 2;

// keep track of the latest duration as it scrolls
const latestDuration = useRef(0);
Expand Down Expand Up @@ -129,10 +154,10 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
flatListRef.current?.scrollToIndex({
animated: options?.animated ?? false,
index: getScrollIndex({
value: value,
numberOfItems,
padWithNItems,
disableInfiniteScroll,
repeatNumbersNTimes,
value: value,
}),
});
},
Expand Down Expand Up @@ -241,10 +266,18 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
// this check stops the feedback firing when the component mounts
if (lastFeedbackIndex.current) {
// fire haptic feedback if available
Haptics?.selectionAsync();
try {
Haptics?.selectionAsync();
} catch {
// do nothing
}

// play click sound if available
clickSound?.replayAsync();
try {
clickSound?.replayAsync();
} catch {
// do nothing
}
}

lastFeedbackIndex.current = feedbackIndex;
Expand Down Expand Up @@ -329,15 +362,16 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
});
} else if (
viewableItems[0]?.index &&
viewableItems[0].index >= numberOfItems * 2.5
viewableItems[0].index >=
numberOfItems * (repeatNumbersNTimes - 0.5)
) {
flatListRef.current?.scrollToIndex({
animated: false,
index: viewableItems[0].index - numberOfItems,
index: viewableItems[0].index - numberOfItems - 1,
});
}
},
[numberOfItems]
[numberOfItems, repeatNumbersNTimes]
);

const getItemLayout = useCallback(
Expand All @@ -352,7 +386,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
const viewabilityConfigCallbackPairs =
useRef<ViewabilityConfigCallbackPairs>([
{
viewabilityConfig: { viewAreaCoveragePercentThreshold: 25 },
viewabilityConfig: { viewAreaCoveragePercentThreshold: 0 },
onViewableItemsChanged: onViewableItemsChanged,
},
]);
Expand Down
1 change: 1 addition & 0 deletions src/components/DurationScroll/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export interface DurationScrollProps {
padWithNItems: number;
pickerGradientOverlayProps?: Partial<LinearGradientProps>;
pmLabel?: string;
repeatNumbersNTimes?: number;
styles: ReturnType<typeof generateStyles>;
testID?: string;
topPickerGradientOverlayProps?: Partial<LinearGradientProps>;
Expand Down
19 changes: 14 additions & 5 deletions src/components/TimerPicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
padWithNItems = 1,
pickerContainerProps,
pmLabel = "pm",
repeatHourNumbersNTimes = 6,
repeatMinuteNumbersNTimes = 3,
repeatSecondNumbersNTimes = 3,
secondLabel,
secondLimit,
secondsPickerIsDisabled = false,
Expand All @@ -59,11 +62,14 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
[checkedPadWithNItems, customStyles]
);

const safeInitialValue = {
hours: initialValue?.hours ?? 0,
minutes: initialValue?.minutes ?? 0,
seconds: initialValue?.seconds ?? 0,
};
const safeInitialValue = useMemo(
() => ({
hours: initialValue?.hours ?? 0,
minutes: initialValue?.minutes ?? 0,
seconds: initialValue?.seconds ?? 0,
}),
[initialValue?.hours, initialValue?.minutes, initialValue?.seconds]
);

const [selectedHours, setSelectedHours] = useState(
safeInitialValue.hours
Expand Down Expand Up @@ -144,6 +150,7 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
padNumbersWithZero={padHoursWithZero}
padWithNItems={checkedPadWithNItems}
pmLabel={pmLabel}
repeatNumbersNTimes={repeatHourNumbersNTimes}
styles={styles}
testID="duration-scroll-hour"
{...otherProps}
Expand All @@ -165,6 +172,7 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
onDurationChange={setSelectedMinutes}
padNumbersWithZero={padMinutesWithZero}
padWithNItems={checkedPadWithNItems}
repeatNumbersNTimes={repeatMinuteNumbersNTimes}
styles={styles}
testID="duration-scroll-minute"
{...otherProps}
Expand All @@ -186,6 +194,7 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
onDurationChange={setSelectedSeconds}
padNumbersWithZero={padSecondsWithZero}
padWithNItems={checkedPadWithNItems}
repeatNumbersNTimes={repeatSecondNumbersNTimes}
styles={styles}
testID="duration-scroll-second"
{...otherProps}
Expand Down
Loading

0 comments on commit dd5168d

Please sign in to comment.