diff --git a/.prettierignore b/.prettierignore
index 9cfabee..80f1432 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -4,3 +4,4 @@ node_modules
.yarn
examples/example-bare/android
examples/example-bare/ios
+*.md
diff --git a/README.md b/README.md
index 600c87f..4c27912 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ Works with Expo and bare React Native apps ✅
Includes iOS-style haptic and audio feedback 🍏
+- [React Native Timer Picker ⏰🕰️⏳](#react-native-timer-picker-️)
- [Demos 📱](#demos-)
- [Installation 🚀](#installation-)
- [Peer Dependencies 👶](#peer-dependencies-)
@@ -289,6 +290,9 @@ return (
setIsVisible={setShowPicker}
styles={{
theme: "light",
+ pickerColumnWidth: {
+ hours: 90,
+ },
}}
use12HourPicker
visible={showPicker}
@@ -426,6 +430,8 @@ return (
setIsVisible={setShowPicker}
styles={{
theme: "dark",
+ pickerLabelGap: 10,
+ text: { fontSize: 18 },
}}
visible={showPicker}
/>
@@ -464,14 +470,13 @@ return (
pickerItem: {
fontSize: 34,
},
- pickerLabelContainer: {
- marginTop: -4,
- right: 0,
- left: undefined,
- },
pickerLabel: {
fontSize: 32,
},
+ pickerLabelContainer: {
+ marginTop: -4,
+ },
+ pickerLabelGap: 23,
pickerContainer: {
paddingHorizontal: 50,
},
@@ -502,7 +507,7 @@ return (
secondLabel="sec"
styles={{
theme: "light",
- labelOffsetPercentage: 0,
+ pickerLabelGap: 8,
pickerItem: {
fontSize: 34,
},
@@ -582,14 +587,18 @@ return (
#### Custom Styles 👗
-The component should look good straight out of the box, but you can use these styles to make it fit in with your App's theme:
+The component should look good straight out of the box, but you can use these easy styles to make it fit in with your App's theme:
+
+| Style Prop | Description | Type |
+| :---------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------: |
+| theme | Theme of the component | "light" \| "dark" |
+| backgroundColor | Main background color | string |
+| text | Base text style | TextStyle |
+| pickerLabelGap | Pixel gap between the label and the picker number column. Can be a single number or a per-column object (e.g. `{ hours: 10, minutes: 8 }`). Default: `6` | `PerColumnValue`\* |
+| pickerColumnWidth | Width of individual picker columns in pixels. Can be a single number or a per-column object. Overrides default flex-based sizing when set | `PerColumnValue`\* |
+| labelOffsetPercentage **(DEPRECATED)** | Percentage offset for horizontal label positioning relative to the picker (use `pickerLabelGap` instead) | number |
-| Style Prop | Description | Type |
-| :-------------------: | :----------------------------------------------------------------------- | :---------------: |
-| theme | Theme of the component | "light" \| "dark" |
-| backgroundColor | Main background color | string |
-| text | Base text style | TextStyle |
-| labelOffsetPercentage | Percentage offset for horizonal label positioning relative to the picker | number |
+**\*`PerColumnValue` type:** `number | { days?: number, hours?: number, minutes?: number, seconds?: number }` — pass a single number for all columns, or an object to set values per column. Omitted columns use the default.
For deeper style customization, you can supply the following custom styles to adjust the component in any way. These are applied on top of the default styling so take a look at those [styles](src/components/TimerPicker/styles.ts) if something isn't adjusting in the way you'd expect.
diff --git a/examples/example-bare/App.tsx b/examples/example-bare/App.tsx
index f0d72c3..8502d40 100644
--- a/examples/example-bare/App.tsx
+++ b/examples/example-bare/App.tsx
@@ -173,6 +173,9 @@ export default function App() {
pickerFeedback={pickerFeedback}
setIsVisible={setShowPickerExample2}
styles={{
+ pickerColumnWidth: {
+ hours: 90,
+ },
theme: "light",
}}
use12HourPicker
@@ -217,6 +220,8 @@ export default function App() {
pickerFeedback={pickerFeedback}
setIsVisible={setShowPickerExample3}
styles={{
+ pickerLabelGap: 10,
+ text: { fontSize: 18 },
theme: "dark",
}}
visible={showPickerExample3}
@@ -253,10 +258,9 @@ export default function App() {
fontSize: 32,
},
pickerLabelContainer: {
- left: undefined,
marginTop: -4,
- right: 0,
},
+ pickerLabelGap: 23,
theme: "dark",
}}
/>
@@ -275,7 +279,6 @@ export default function App() {
pickerFeedback={pickerFeedback}
secondLabel="sec"
styles={{
- labelOffsetPercentage: 0,
pickerContainer: {
paddingHorizontal: 50,
},
@@ -285,6 +288,7 @@ export default function App() {
pickerLabel: {
fontSize: 26,
},
+ pickerLabelGap: 8,
theme: "light",
}}
/>
diff --git a/examples/example-expo/App.tsx b/examples/example-expo/App.tsx
index 7a72534..4542332 100644
--- a/examples/example-expo/App.tsx
+++ b/examples/example-expo/App.tsx
@@ -119,7 +119,6 @@ export default function App() {
@@ -206,7 +210,11 @@ export default function App() {
}}
pickerFeedback={pickerFeedback}
setIsVisible={setShowPickerExample3}
- styles={{ theme: "dark" }}
+ styles={{
+ pickerLabelGap: 10,
+ text: { fontWeight: "bold" },
+ theme: "dark",
+ }}
visible={showPickerExample3}
/>
@@ -241,10 +249,9 @@ export default function App() {
fontSize: 32,
},
pickerLabelContainer: {
- left: undefined,
marginTop: -4,
- right: 0,
},
+ pickerLabelGap: 23,
theme: "dark",
}}
/>
@@ -263,7 +270,6 @@ export default function App() {
pickerFeedback={pickerFeedback}
secondLabel="sec"
styles={{
- labelOffsetPercentage: 0,
pickerContainer: {
paddingHorizontal: 50,
},
@@ -273,6 +279,7 @@ export default function App() {
pickerLabel: {
fontSize: 26,
},
+ pickerLabelGap: 8,
theme: "light",
}}
/>
@@ -350,6 +357,7 @@ export default function App() {
horizontal
onMomentumScrollEnd={onMomentumScrollEnd}
pagingEnabled
+ showsHorizontalScrollIndicator={false}
>
{renderExample1}
{renderExample2}
diff --git a/package.json b/package.json
index 90fa1ce..7ace772 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"url": "https://github.com/troberts-28"
},
"license": "MIT",
- "version": "2.5.0",
+ "version": "2.6.0",
"main": "dist/commonjs/index.js",
"module": "dist/module/index.js",
"types": "dist/typescript/index.d.ts",
@@ -30,7 +30,7 @@
"lint:fix": "eslint src/ examples/ --fix",
"format": "prettier --check ./src ./examples",
"format:fix": "prettier --write ./src ./examples",
- "prepare": "yarn build"
+ "prepare": "simple-git-hooks"
},
"homepage": "https://github.com/troberts-28/react-native-timer-picker",
"bugs": {
@@ -108,12 +108,14 @@
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
"jest": "^29.0.0",
+ "lint-staged": "^16.2.7",
"metro-react-native-babel-preset": "^0.71.1",
"prettier": "2.8.8",
"react": "18.2.0",
"react-native": "0.72.0",
"react-native-builder-bob": "^0.18.3",
"react-test-renderer": "18.2.0",
+ "simple-git-hooks": "^2.13.1",
"typescript": "~5.8.0",
"typescript-eslint": "^8.33.0"
},
@@ -126,6 +128,18 @@
"typescript"
]
},
+ "simple-git-hooks": {
+ "pre-commit": "npx lint-staged"
+ },
+ "lint-staged": {
+ "*.{ts,tsx,js,jsx}": [
+ "eslint --fix",
+ "prettier --write"
+ ],
+ "*.{json}": [
+ "prettier --write"
+ ]
+ },
"eslintIgnore": [
"node_modules/",
"dist/"
diff --git a/src/components/DurationScroll/DurationScroll.tsx b/src/components/DurationScroll/DurationScroll.tsx
index 1867bc0..ca2da04 100644
--- a/src/components/DurationScroll/DurationScroll.tsx
+++ b/src/components/DurationScroll/DurationScroll.tsx
@@ -45,8 +45,10 @@ const DurationScroll = forwardRef((props
onDurationChange,
padNumbersWithZero = false,
padWithNItems,
+ pickerColumnWidth,
pickerFeedback,
pickerGradientOverlayProps,
+ pickerLabelGap,
pmLabel,
repeatNumbersNTimes = 3,
repeatNumbersNTimesNotExplicitlySet,
@@ -55,6 +57,24 @@ const DurationScroll = forwardRef((props
testID,
} = props;
+ const labelPositionStyle = useMemo(() => {
+ // When the style already has an explicit `left` (from legacy percentage system or
+ // user override), don't apply pixel-based positioning.
+ if (styles.pickerLabelContainer.left != null) {
+ return undefined;
+ }
+
+ const gap = pickerLabelGap ?? 6;
+ const fontSize = styles.pickerItem.fontSize ?? 25;
+ const maxDigitCount = Math.max(2, String(maximumValue).length);
+ const halfNumberWidth = (maxDigitCount * fontSize * 0.55) / 2;
+
+ return {
+ left: "50%" as const,
+ marginLeft: halfNumberWidth + gap,
+ };
+ }, [maximumValue, pickerLabelGap, styles.pickerItem.fontSize, styles.pickerLabelContainer.left]);
+
const numberOfItems = useMemo(() => {
// guard against negative maximum values
if (maximumValue < 0) {
@@ -210,6 +230,7 @@ const DurationScroll = forwardRef((props
amLabel={amLabel}
is12HourPicker={is12HourPicker}
item={item}
+ pickerAmPmPositionStyle={labelPositionStyle}
pmLabel={pmLabel}
selectedValue={selectedValue}
styles={styles}
@@ -221,6 +242,7 @@ const DurationScroll = forwardRef((props
allowFontScaling,
amLabel,
is12HourPicker,
+ labelPositionStyle,
pmLabel,
selectedValue,
styles,
@@ -488,7 +510,7 @@ const DurationScroll = forwardRef((props
viewabilityConfigCallbackPairs={viewabilityConfigCallbackPairs}
windowSize={numberOfItemsToShow}
/>
-
+
{typeof label === "string" ? (
{label}
@@ -508,6 +530,7 @@ const DurationScroll = forwardRef((props
initialScrollIndex,
isDisabled,
label,
+ labelPositionStyle,
numberOfItemsToShow,
numbersForFlatList,
onMomentumScrollEnd,
@@ -571,6 +594,7 @@ const DurationScroll = forwardRef((props
pointerEvents={isDisabled ? "none" : undefined}
style={[
styles.durationScrollFlatListContainer,
+ pickerColumnWidth != null && { flex: 0, width: pickerColumnWidth },
{
height: styles.pickerItemContainer.height * numberOfItemsToShow,
},
diff --git a/src/components/DurationScroll/types.ts b/src/components/DurationScroll/types.ts
index d4e7f2a..0bd2030 100644
--- a/src/components/DurationScroll/types.ts
+++ b/src/components/DurationScroll/types.ts
@@ -28,8 +28,10 @@ export interface DurationScrollProps {
onDurationChange: (duration: number) => void;
padNumbersWithZero?: boolean;
padWithNItems: number;
+ pickerColumnWidth?: number;
pickerFeedback?: () => void | Promise;
pickerGradientOverlayProps?: Partial;
+ pickerLabelGap?: number;
pmLabel?: string;
repeatNumbersNTimes?: number;
repeatNumbersNTimesNotExplicitlySet: boolean;
diff --git a/src/components/PickerItem/PickerItem.tsx b/src/components/PickerItem/PickerItem.tsx
index 73aae7b..0d764ca 100644
--- a/src/components/PickerItem/PickerItem.tsx
+++ b/src/components/PickerItem/PickerItem.tsx
@@ -11,6 +11,7 @@ interface PickerItemProps {
amLabel?: string;
is12HourPicker?: boolean;
item: string;
+ pickerAmPmPositionStyle?: { left: "50%"; marginLeft: number };
pmLabel?: string;
selectedValue?: number;
styles: ReturnType;
@@ -24,6 +25,7 @@ const PickerItem = React.memo(
amLabel,
is12HourPicker,
item,
+ pickerAmPmPositionStyle,
pmLabel,
selectedValue,
styles,
@@ -57,7 +59,7 @@ const PickerItem = React.memo(
{stringItem}
{is12HourPicker && (
-
+
{isAm ? amLabel : pmLabel}
diff --git a/src/components/TimerPicker/TimerPicker.tsx b/src/components/TimerPicker/TimerPicker.tsx
index 4e95c6e..43af37c 100644
--- a/src/components/TimerPicker/TimerPicker.tsx
+++ b/src/components/TimerPicker/TimerPicker.tsx
@@ -13,8 +13,24 @@ import { getSafeInitialValue } from "../../utils/getSafeInitialValue";
import DurationScroll from "../DurationScroll";
import type { DurationScrollRef } from "../DurationScroll";
import { generateStyles } from "./styles";
+import type { PerColumnValue, PickerColumn } from "./styles";
import type { TimerPickerProps, TimerPickerRef } from "./types";
+const resolvePerColumn = (
+ value: PerColumnValue | undefined,
+ column: PickerColumn
+): number | undefined => {
+ if (value == null) {
+ return undefined;
+ }
+
+ if (typeof value === "number") {
+ return value;
+ }
+
+ return value[column];
+};
+
const TimerPicker = forwardRef((props, ref) => {
const {
aggressivelyGetLatestDuration = false,
@@ -80,7 +96,24 @@ const TimerPicker = forwardRef((props, ref) =>
'The "clickSoundAsset" prop is deprecated and will be removed in a future version. Please use the "pickerFeedback" prop instead.'
);
}
- }, [otherProps.Audio, otherProps.Haptics, otherProps.clickSoundAsset]);
+ if (customStyles?.labelOffsetPercentage != null) {
+ if (customStyles?.pickerLabelGap != null) {
+ console.warn(
+ "labelOffsetPercentage is ignored when pickerLabelGap is set. Please remove labelOffsetPercentage."
+ );
+ } else {
+ console.warn(
+ 'The "labelOffsetPercentage" style prop is deprecated and will be removed in a future version. Please use the "pickerLabelGap" style prop instead.'
+ );
+ }
+ }
+ }, [
+ otherProps.Audio,
+ otherProps.Haptics,
+ otherProps.clickSoundAsset,
+ customStyles?.labelOffsetPercentage,
+ customStyles?.pickerLabelGap,
+ ]);
const safePadWithNItems = useMemo(() => {
if (padWithNItems < 0 || isNaN(padWithNItems)) {
@@ -107,6 +140,9 @@ const TimerPicker = forwardRef((props, ref) =>
[initialValue?.days, initialValue?.hours, initialValue?.minutes, initialValue?.seconds]
);
+ const pickerLabelGap = customStyles?.pickerLabelGap;
+ const pickerColumnWidth = customStyles?.pickerColumnWidth;
+
const styles = useMemo(
() => generateStyles(customStyles),
@@ -187,6 +223,8 @@ const TimerPicker = forwardRef((props, ref) =>
onDurationChange={setSelectedDays}
padNumbersWithZero={padDaysWithZero}
padWithNItems={safePadWithNItems}
+ pickerColumnWidth={resolvePerColumn(pickerColumnWidth, "days")}
+ pickerLabelGap={resolvePerColumn(pickerLabelGap, "days")}
repeatNumbersNTimes={repeatDayNumbersNTimes}
repeatNumbersNTimesNotExplicitlySet={props?.repeatDayNumbersNTimes === undefined}
selectedValue={selectedDays}
@@ -213,6 +251,8 @@ const TimerPicker = forwardRef((props, ref) =>
onDurationChange={setSelectedHours}
padNumbersWithZero={padHoursWithZero}
padWithNItems={safePadWithNItems}
+ pickerColumnWidth={resolvePerColumn(pickerColumnWidth, "hours")}
+ pickerLabelGap={resolvePerColumn(pickerLabelGap, "hours")}
pmLabel={pmLabel}
repeatNumbersNTimes={repeatHourNumbersNTimes}
repeatNumbersNTimesNotExplicitlySet={props?.repeatHourNumbersNTimes === undefined}
@@ -238,6 +278,8 @@ const TimerPicker = forwardRef((props, ref) =>
onDurationChange={setSelectedMinutes}
padNumbersWithZero={padMinutesWithZero}
padWithNItems={safePadWithNItems}
+ pickerColumnWidth={resolvePerColumn(pickerColumnWidth, "minutes")}
+ pickerLabelGap={resolvePerColumn(pickerLabelGap, "minutes")}
repeatNumbersNTimes={repeatMinuteNumbersNTimes}
repeatNumbersNTimesNotExplicitlySet={props?.repeatMinuteNumbersNTimes === undefined}
selectedValue={selectedMinutes}
@@ -262,6 +304,8 @@ const TimerPicker = forwardRef((props, ref) =>
onDurationChange={setSelectedSeconds}
padNumbersWithZero={padSecondsWithZero}
padWithNItems={safePadWithNItems}
+ pickerColumnWidth={resolvePerColumn(pickerColumnWidth, "seconds")}
+ pickerLabelGap={resolvePerColumn(pickerLabelGap, "seconds")}
repeatNumbersNTimes={repeatSecondNumbersNTimes}
repeatNumbersNTimesNotExplicitlySet={props?.repeatSecondNumbersNTimes === undefined}
selectedValue={selectedSeconds}
diff --git a/src/components/TimerPicker/styles.ts b/src/components/TimerPicker/styles.ts
index ba1c7a4..cf4da5f 100644
--- a/src/components/TimerPicker/styles.ts
+++ b/src/components/TimerPicker/styles.ts
@@ -1,6 +1,10 @@
import { StyleSheet } from "react-native";
import type { TextStyle, ViewStyle } from "react-native";
+export type PickerColumn = "days" | "hours" | "minutes" | "seconds";
+
+export type PerColumnValue = number | Partial>;
+
export interface CustomTimerPickerStyles {
backgroundColor?: string;
disabledPickerContainer?: ViewStyle;
@@ -8,15 +12,18 @@ export interface CustomTimerPickerStyles {
durationScrollFlatList?: ViewStyle;
durationScrollFlatListContainer?: ViewStyle;
durationScrollFlatListContentContainer?: ViewStyle;
+ /** @deprecated Use pickerLabelGap instead. Will be removed in a future version. */
labelOffsetPercentage?: number;
pickerAmPmContainer?: ViewStyle;
pickerAmPmLabel?: TextStyle;
+ pickerColumnWidth?: PerColumnValue;
pickerContainer?: ViewStyle & { backgroundColor?: string };
pickerGradientOverlay?: ViewStyle;
pickerItem?: TextStyle;
pickerItemContainer?: ViewStyle & { height?: number };
pickerLabel?: TextStyle;
pickerLabelContainer?: ViewStyle;
+ pickerLabelGap?: PerColumnValue;
selectedPickerItem?: TextStyle;
text?: TextStyle;
theme?: "light" | "dark";
@@ -49,9 +56,13 @@ export const generateStyles = (customStyles: CustomTimerPickerStyles | undefined
const pickerLabelVerticalOffset = pickerItemFontSize - pickerLabelFontSize - 1;
const pickerAmPmVerticalOffset = pickerItemFontSize - pickerAmPmFontSize - 1;
- // The label is absolutely positioned, so we need to offset it for it to appear
- // in the correct position. We offset it to the left of the container so that
- // the width of the label doesn't impact its position.
+ // Determine whether to use the legacy percentage-based label positioning.
+ // The new pixel-based system (pickerLabelGap) is the default.
+ // The old system is only used when labelOffsetPercentage is explicitly set
+ // without pickerLabelGap.
+ const useLegacyLabelPosition =
+ customStyles?.labelOffsetPercentage != null && customStyles?.pickerLabelGap == null;
+
const extraLabelOffsetPercentage = customStyles?.labelOffsetPercentage ?? 8;
const baseLeftOffsetPercentage = 70;
const labelOffsetPercentage = baseLeftOffsetPercentage + extraLabelOffsetPercentage;
@@ -85,10 +96,12 @@ export const generateStyles = (customStyles: CustomTimerPickerStyles | undefined
pickerAmPmContainer: {
bottom: 0,
justifyContent: "center",
- left: `${labelOffsetPercentage}%`,
marginTop: pickerAmPmVerticalOffset,
position: "absolute",
top: 0,
+ // Only apply percentage-based left when using legacy positioning.
+ // The new pixel-based positioning is applied per-column in PickerItem.
+ ...(useLegacyLabelPosition ? { left: `${labelOffsetPercentage}%` } : undefined),
...customStyles?.pickerLabelContainer,
...customStyles?.pickerAmPmContainer,
},
@@ -137,10 +150,12 @@ export const generateStyles = (customStyles: CustomTimerPickerStyles | undefined
pickerLabelContainer: {
bottom: 0,
justifyContent: "center",
- left: `${labelOffsetPercentage}%`,
marginTop: pickerLabelVerticalOffset,
position: "absolute",
top: 0,
+ // Only apply percentage-based left when using legacy positioning.
+ // The new pixel-based positioning is applied per-column in DurationScroll.
+ ...(useLegacyLabelPosition ? { left: `${labelOffsetPercentage}%` } : undefined),
...customStyles?.pickerLabelContainer,
},
selectedPickerItem: {
diff --git a/src/components/TimerPickerModal/TimerPickerModal.tsx b/src/components/TimerPickerModal/TimerPickerModal.tsx
index 31aa195..022568e 100644
--- a/src/components/TimerPickerModal/TimerPickerModal.tsx
+++ b/src/components/TimerPickerModal/TimerPickerModal.tsx
@@ -13,9 +13,25 @@ import { getSafeInitialValue } from "../../utils/getSafeInitialValue";
import Modal from "../Modal";
import TimerPicker from "../TimerPicker";
import type { TimerPickerRef } from "../TimerPicker";
-import { generateStyles } from "./styles";
+import type { PerColumnValue, PickerColumn } from "../TimerPicker/styles";
+import { DEFAULT_COLUMN_WIDTH, generateStyles } from "./styles";
import type { TimerPickerModalRef, TimerPickerModalProps } from "./types";
+const resolveColumnWidth = (
+ pickerColumnWidth: PerColumnValue | undefined,
+ column: PickerColumn
+): number => {
+ if (pickerColumnWidth == null) {
+ return DEFAULT_COLUMN_WIDTH;
+ }
+
+ if (typeof pickerColumnWidth === "number") {
+ return pickerColumnWidth;
+ }
+
+ return pickerColumnWidth[column] ?? DEFAULT_COLUMN_WIDTH;
+};
+
const TimerPickerModal = forwardRef((props, ref) => {
const {
buttonContainerProps,
@@ -26,6 +42,10 @@ const TimerPickerModal = forwardRef(
containerProps,
contentContainerProps,
hideCancelButton = false,
+ hideDays = true,
+ hideHours = false,
+ hideMinutes = false,
+ hideSeconds = false,
initialValue,
modalProps,
modalTitle,
@@ -39,8 +59,17 @@ const TimerPickerModal = forwardRef(
...otherProps
} = props;
+ const pickerColumnWidth = customStyles?.pickerColumnWidth;
+
+ const totalColumnWidth =
+ (!hideDays ? resolveColumnWidth(pickerColumnWidth, "days") : 0) +
+ (!hideHours ? resolveColumnWidth(pickerColumnWidth, "hours") : 0) +
+ (!hideMinutes ? resolveColumnWidth(pickerColumnWidth, "minutes") : 0) +
+ (!hideSeconds ? resolveColumnWidth(pickerColumnWidth, "seconds") : 0);
+
const styles = generateStyles(customStyles, {
hasModalTitle: Boolean(modalTitle),
+ totalColumnWidth,
});
const timerPickerRef = useRef(null);
@@ -147,6 +176,10 @@ const TimerPickerModal = forwardRef(
) : null}
{
const {
@@ -35,6 +38,14 @@ export const generateStyles = (
...customTimerPickerStyles
} = customStyles ?? {};
+ const totalColumnWidth = variables.totalColumnWidth;
+ const modalPadding = (customContentContainerStyle?.paddingHorizontal as number) ?? 20;
+ const labelOverhang = 20;
+ const computedWidth = Math.max(
+ DEFAULT_COLUMN_WIDTH * 2,
+ totalColumnWidth + modalPadding * 2 + labelOverhang
+ );
+
return StyleSheet.create({
button: {
borderRadius: 10,
@@ -83,6 +94,7 @@ export const generateStyles = (
justifyContent: "center",
overflow: "hidden",
paddingHorizontal: 20,
+ width: computedWidth,
...customContentContainerStyle,
},
modalTitle: {
diff --git a/yarn.lock b/yarn.lock
index 7564f86..eda073a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4450,6 +4450,15 @@ __metadata:
languageName: node
linkType: hard
+"ansi-escapes@npm:^7.0.0":
+ version: 7.3.0
+ resolution: "ansi-escapes@npm:7.3.0"
+ dependencies:
+ environment: "npm:^1.0.0"
+ checksum: 10c0/068961d99f0ef28b661a4a9f84a5d645df93ccf3b9b93816cc7d46bbe1913321d4cdf156bb842a4e1e4583b7375c631fa963efb43001c4eb7ff9ab8f78fc0679
+ languageName: node
+ linkType: hard
+
"ansi-fragments@npm:^0.2.1":
version: 0.2.1
resolution: "ansi-fragments@npm:0.2.1"
@@ -4514,6 +4523,13 @@ __metadata:
languageName: node
linkType: hard
+"ansi-styles@npm:^6.2.1":
+ version: 6.2.3
+ resolution: "ansi-styles@npm:6.2.3"
+ checksum: 10c0/23b8a4ce14e18fb854693b95351e286b771d23d8844057ed2e7d083cd3e708376c3323707ec6a24365f7d7eda3ca00327fe04092e29e551499ec4c8b7bfac868
+ languageName: node
+ linkType: hard
+
"any-promise@npm:^1.0.0":
version: 1.3.0
resolution: "any-promise@npm:1.3.0"
@@ -5385,6 +5401,15 @@ __metadata:
languageName: node
linkType: hard
+"cli-cursor@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "cli-cursor@npm:5.0.0"
+ dependencies:
+ restore-cursor: "npm:^5.0.0"
+ checksum: 10c0/7ec62f69b79f6734ab209a3e4dbdc8af7422d44d360a7cb1efa8a0887bbe466a6e625650c466fe4359aee44dbe2dc0b6994b583d40a05d0808a5cb193641d220
+ languageName: node
+ linkType: hard
+
"cli-spinners@npm:^2.0.0, cli-spinners@npm:^2.5.0":
version: 2.9.2
resolution: "cli-spinners@npm:2.9.2"
@@ -5392,6 +5417,16 @@ __metadata:
languageName: node
linkType: hard
+"cli-truncate@npm:^5.0.0":
+ version: 5.1.1
+ resolution: "cli-truncate@npm:5.1.1"
+ dependencies:
+ slice-ansi: "npm:^7.1.0"
+ string-width: "npm:^8.0.0"
+ checksum: 10c0/3842920829a62f3e041ce39199050c42706c3c9c756a4efc8b86d464e102d1fa031d8b1b9b2e3bb36e1017c763558275472d031bdc884c1eff22a2f20e4f6b0a
+ languageName: node
+ linkType: hard
+
"cliui@npm:^6.0.0":
version: 6.0.0
resolution: "cliui@npm:6.0.0"
@@ -5485,6 +5520,13 @@ __metadata:
languageName: node
linkType: hard
+"colorette@npm:^2.0.20":
+ version: 2.0.20
+ resolution: "colorette@npm:2.0.20"
+ checksum: 10c0/e94116ff33b0ff56f3b83b9ace895e5bf87c2a7a47b3401b8c3f3226e050d5ef76cf4072fb3325f9dc24d1698f9b730baf4e05eeaf861d74a1883073f4c98a40
+ languageName: node
+ linkType: hard
+
"command-exists@npm:^1.2.8":
version: 1.2.9
resolution: "command-exists@npm:1.2.9"
@@ -5499,6 +5541,13 @@ __metadata:
languageName: node
linkType: hard
+"commander@npm:^14.0.2":
+ version: 14.0.3
+ resolution: "commander@npm:14.0.3"
+ checksum: 10c0/755652564bbf56ff2ff083313912b326450d3f8d8c85f4b71416539c9a05c3c67dbd206821ca72635bf6b160e2afdefcb458e86b317827d5cb333b69ce7f1a24
+ languageName: node
+ linkType: hard
+
"commander@npm:^2.20.0":
version: 2.20.3
resolution: "commander@npm:2.20.3"
@@ -6021,6 +6070,13 @@ __metadata:
languageName: node
linkType: hard
+"emoji-regex@npm:^10.3.0":
+ version: 10.6.0
+ resolution: "emoji-regex@npm:10.6.0"
+ checksum: 10c0/1e4aa097bb007301c3b4b1913879ae27327fdc48e93eeefefe3b87e495eb33c5af155300be951b4349ff6ac084f4403dc9eff970acba7c1c572d89396a9a32d7
+ languageName: node
+ linkType: hard
+
"emoji-regex@npm:^8.0.0":
version: 8.0.0
resolution: "emoji-regex@npm:8.0.0"
@@ -6099,6 +6155,13 @@ __metadata:
languageName: node
linkType: hard
+"environment@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "environment@npm:1.1.0"
+ checksum: 10c0/fb26434b0b581ab397039e51ff3c92b34924a98b2039dcb47e41b7bca577b9dbf134a8eadb364415c74464b682e2d3afe1a4c0eb9873dc44ea814c5d3103331d
+ languageName: node
+ linkType: hard
+
"err-code@npm:^2.0.2":
version: 2.0.3
resolution: "err-code@npm:2.0.3"
@@ -6640,6 +6703,13 @@ __metadata:
languageName: node
linkType: hard
+"eventemitter3@npm:^5.0.1":
+ version: 5.0.4
+ resolution: "eventemitter3@npm:5.0.4"
+ checksum: 10c0/575b8cac8d709e1473da46f8f15ef311b57ff7609445a7c71af5cd42598583eee6f098fa7a593e30f27e94b8865642baa0689e8fa97c016f742abdb3b1bf6d9a
+ languageName: node
+ linkType: hard
+
"example-bare@workspace:examples/example-bare":
version: 0.0.0-use.local
resolution: "example-bare@workspace:examples/example-bare"
@@ -7272,6 +7342,13 @@ __metadata:
languageName: node
linkType: hard
+"get-east-asian-width@npm:^1.0.0, get-east-asian-width@npm:^1.3.1, get-east-asian-width@npm:^1.5.0":
+ version: 1.5.0
+ resolution: "get-east-asian-width@npm:1.5.0"
+ checksum: 10c0/bff8bbc8d81790b9477f7aa55b1806b9f082a8dc1359fff7bd8b96939622c86b729685afc2bfeb22def1fc6ef1e5228e4d87dd4e6da60bc43a5edfb03c4ee167
+ languageName: node
+ linkType: hard
+
"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0":
version: 1.3.0
resolution: "get-intrinsic@npm:1.3.0"
@@ -8004,6 +8081,15 @@ __metadata:
languageName: node
linkType: hard
+"is-fullwidth-code-point@npm:^5.0.0":
+ version: 5.1.0
+ resolution: "is-fullwidth-code-point@npm:5.1.0"
+ dependencies:
+ get-east-asian-width: "npm:^1.3.1"
+ checksum: 10c0/c1172c2e417fb73470c56c431851681591f6a17233603a9e6f94b7ba870b2e8a5266506490573b607fb1081318589372034aa436aec07b465c2029c0bc7f07a4
+ languageName: node
+ linkType: hard
+
"is-generator-fn@npm:^2.0.0":
version: 2.1.0
resolution: "is-generator-fn@npm:2.1.0"
@@ -9269,6 +9355,37 @@ __metadata:
languageName: node
linkType: hard
+"lint-staged@npm:^16.2.7":
+ version: 16.2.7
+ resolution: "lint-staged@npm:16.2.7"
+ dependencies:
+ commander: "npm:^14.0.2"
+ listr2: "npm:^9.0.5"
+ micromatch: "npm:^4.0.8"
+ nano-spawn: "npm:^2.0.0"
+ pidtree: "npm:^0.6.0"
+ string-argv: "npm:^0.3.2"
+ yaml: "npm:^2.8.1"
+ bin:
+ lint-staged: bin/lint-staged.js
+ checksum: 10c0/9a677c21a8112d823ae5bc565ba2c9e7b803786f2a021c46827a55fe44ed59def96edb24fc99c06a2545cdbbf366022ad82addcb3bf60c712f3b98ef92069717
+ languageName: node
+ linkType: hard
+
+"listr2@npm:^9.0.5":
+ version: 9.0.5
+ resolution: "listr2@npm:9.0.5"
+ dependencies:
+ cli-truncate: "npm:^5.0.0"
+ colorette: "npm:^2.0.20"
+ eventemitter3: "npm:^5.0.1"
+ log-update: "npm:^6.1.0"
+ rfdc: "npm:^1.4.1"
+ wrap-ansi: "npm:^9.0.0"
+ checksum: 10c0/46448d1ba0addc9d71aeafd05bb8e86ded9641ccad930ac302c2bd2ad71580375604743e18586fcb8f11906edf98e8e17fca75ba0759947bf275d381f68e311d
+ languageName: node
+ linkType: hard
+
"locate-path@npm:^3.0.0":
version: 3.0.0
resolution: "locate-path@npm:3.0.0"
@@ -9344,6 +9461,19 @@ __metadata:
languageName: node
linkType: hard
+"log-update@npm:^6.1.0":
+ version: 6.1.0
+ resolution: "log-update@npm:6.1.0"
+ dependencies:
+ ansi-escapes: "npm:^7.0.0"
+ cli-cursor: "npm:^5.0.0"
+ slice-ansi: "npm:^7.1.0"
+ strip-ansi: "npm:^7.1.0"
+ wrap-ansi: "npm:^9.0.0"
+ checksum: 10c0/4b350c0a83d7753fea34dcac6cd797d1dc9603291565de009baa4aa91c0447eab0d3815a05c8ec9ac04fdfffb43c82adcdb03ec1fceafd8518e1a8c1cff4ff89
+ languageName: node
+ linkType: hard
+
"logkitty@npm:^0.7.1":
version: 0.7.1
resolution: "logkitty@npm:0.7.1"
@@ -10360,6 +10490,13 @@ __metadata:
languageName: node
linkType: hard
+"mimic-function@npm:^5.0.0":
+ version: 5.0.1
+ resolution: "mimic-function@npm:5.0.1"
+ checksum: 10c0/f3d9464dd1816ecf6bdf2aec6ba32c0728022039d992f178237d8e289b48764fee4131319e72eedd4f7f094e22ded0af836c3187a7edc4595d28dd74368fd81d
+ languageName: node
+ linkType: hard
+
"min-indent@npm:^1.0.0":
version: 1.0.1
resolution: "min-indent@npm:1.0.1"
@@ -10558,6 +10695,13 @@ __metadata:
languageName: node
linkType: hard
+"nano-spawn@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "nano-spawn@npm:2.0.0"
+ checksum: 10c0/d00f9b5739f86e28cb732ffd774793e110810cded246b8393c75c4f22674af47f98ee37b19f022ada2d8c9425f800e841caa0662fbff4c0930a10e39339fb366
+ languageName: node
+ linkType: hard
+
"nanoid@npm:^3.3.7":
version: 3.3.11
resolution: "nanoid@npm:3.3.11"
@@ -10902,6 +11046,15 @@ __metadata:
languageName: node
linkType: hard
+"onetime@npm:^7.0.0":
+ version: 7.0.0
+ resolution: "onetime@npm:7.0.0"
+ dependencies:
+ mimic-function: "npm:^5.0.0"
+ checksum: 10c0/5cb9179d74b63f52a196a2e7037ba2b9a893245a5532d3f44360012005c9cadb60851d56716ebff18a6f47129dab7168022445df47c2aff3b276d92585ed1221
+ languageName: node
+ linkType: hard
+
"open@npm:^6.2.0":
version: 6.4.0
resolution: "open@npm:6.4.0"
@@ -11207,6 +11360,15 @@ __metadata:
languageName: node
linkType: hard
+"pidtree@npm:^0.6.0":
+ version: 0.6.0
+ resolution: "pidtree@npm:0.6.0"
+ bin:
+ pidtree: bin/pidtree.js
+ checksum: 10c0/0829ec4e9209e230f74ebf4265f5ccc9ebfb488334b525cb13f86ff801dca44b362c41252cd43ae4d7653a10a5c6ab3be39d2c79064d6895e0d78dc50a5ed6e9
+ languageName: node
+ linkType: hard
+
"pify@npm:^4.0.1":
version: 4.0.1
resolution: "pify@npm:4.0.1"
@@ -11653,12 +11815,14 @@ __metadata:
eslint-plugin-react: "npm:^7.37.5"
eslint-plugin-react-hooks: "npm:^5.2.0"
jest: "npm:^29.0.0"
+ lint-staged: "npm:^16.2.7"
metro-react-native-babel-preset: "npm:^0.71.1"
prettier: "npm:2.8.8"
react: "npm:18.2.0"
react-native: "npm:0.72.0"
react-native-builder-bob: "npm:^0.18.3"
react-test-renderer: "npm:18.2.0"
+ simple-git-hooks: "npm:^2.13.1"
typescript: "npm:~5.8.0"
typescript-eslint: "npm:^8.33.0"
peerDependencies:
@@ -12194,6 +12358,16 @@ __metadata:
languageName: node
linkType: hard
+"restore-cursor@npm:^5.0.0":
+ version: 5.1.0
+ resolution: "restore-cursor@npm:5.1.0"
+ dependencies:
+ onetime: "npm:^7.0.0"
+ signal-exit: "npm:^4.1.0"
+ checksum: 10c0/c2ba89131eea791d1b25205bdfdc86699767e2b88dee2a590b1a6caa51737deac8bad0260a5ded2f7c074b7db2f3a626bcf1fcf3cdf35974cbeea5e2e6764f60
+ languageName: node
+ linkType: hard
+
"retry@npm:^0.12.0":
version: 0.12.0
resolution: "retry@npm:0.12.0"
@@ -12208,6 +12382,13 @@ __metadata:
languageName: node
linkType: hard
+"rfdc@npm:^1.4.1":
+ version: 1.4.1
+ resolution: "rfdc@npm:1.4.1"
+ checksum: 10c0/4614e4292356cafade0b6031527eea9bc90f2372a22c012313be1dcc69a3b90c7338158b414539be863fa95bfcb2ddcd0587be696841af4e6679d85e62c060c7
+ languageName: node
+ linkType: hard
+
"rimraf@npm:^3.0.2":
version: 3.0.2
resolution: "rimraf@npm:3.0.2"
@@ -12575,13 +12756,22 @@ __metadata:
languageName: node
linkType: hard
-"signal-exit@npm:^4.0.1":
+"signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0":
version: 4.1.0
resolution: "signal-exit@npm:4.1.0"
checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83
languageName: node
linkType: hard
+"simple-git-hooks@npm:^2.13.1":
+ version: 2.13.1
+ resolution: "simple-git-hooks@npm:2.13.1"
+ bin:
+ simple-git-hooks: cli.js
+ checksum: 10c0/09631ce2cce5c6cf91f5a990bbefce88f95589ce112a601e2745b8e10ea951668c13f89b3fab2044506646380dcc91b618bb400d35142873a1990c4528b456bb
+ languageName: node
+ linkType: hard
+
"simple-plist@npm:^1.1.0":
version: 1.4.0
resolution: "simple-plist@npm:1.4.0"
@@ -12618,6 +12808,16 @@ __metadata:
languageName: node
linkType: hard
+"slice-ansi@npm:^7.1.0":
+ version: 7.1.2
+ resolution: "slice-ansi@npm:7.1.2"
+ dependencies:
+ ansi-styles: "npm:^6.2.1"
+ is-fullwidth-code-point: "npm:^5.0.0"
+ checksum: 10c0/36742f2eb0c03e2e81a38ed14d13a64f7b732fe38c3faf96cce0599788a345011e840db35f1430ca606ea3f8db2abeb92a8d25c2753a819e3babaa10c2e289a2
+ languageName: node
+ linkType: hard
+
"slugify@npm:^1.3.4, slugify@npm:^1.6.6":
version: 1.6.6
resolution: "slugify@npm:1.6.6"
@@ -12770,6 +12970,13 @@ __metadata:
languageName: node
linkType: hard
+"string-argv@npm:^0.3.2":
+ version: 0.3.2
+ resolution: "string-argv@npm:0.3.2"
+ checksum: 10c0/75c02a83759ad1722e040b86823909d9a2fc75d15dd71ec4b537c3560746e33b5f5a07f7332d1e3f88319909f82190843aa2f0a0d8c8d591ec08e93d5b8dec82
+ languageName: node
+ linkType: hard
+
"string-length@npm:^4.0.1":
version: 4.0.2
resolution: "string-length@npm:4.0.2"
@@ -12809,6 +13016,27 @@ __metadata:
languageName: node
linkType: hard
+"string-width@npm:^7.0.0":
+ version: 7.2.0
+ resolution: "string-width@npm:7.2.0"
+ dependencies:
+ emoji-regex: "npm:^10.3.0"
+ get-east-asian-width: "npm:^1.0.0"
+ strip-ansi: "npm:^7.1.0"
+ checksum: 10c0/eb0430dd43f3199c7a46dcbf7a0b34539c76fe3aa62763d0b0655acdcbdf360b3f66f3d58ca25ba0205f42ea3491fa00f09426d3b7d3040e506878fc7664c9b9
+ languageName: node
+ linkType: hard
+
+"string-width@npm:^8.0.0":
+ version: 8.2.0
+ resolution: "string-width@npm:8.2.0"
+ dependencies:
+ get-east-asian-width: "npm:^1.5.0"
+ strip-ansi: "npm:^7.1.2"
+ checksum: 10c0/d8915428b43519b0f494da6590dbe4491857d8a12e40250e50fc01fbb616ffd8400a436bbe25712255ee129511fe0414c49d3b6b9627e2bc3a33dcec1d2eda02
+ languageName: node
+ linkType: hard
+
"string.prototype.matchall@npm:^4.0.12":
version: 4.0.12
resolution: "string.prototype.matchall@npm:4.0.12"
@@ -12923,6 +13151,15 @@ __metadata:
languageName: node
linkType: hard
+"strip-ansi@npm:^7.1.0, strip-ansi@npm:^7.1.2":
+ version: 7.1.2
+ resolution: "strip-ansi@npm:7.1.2"
+ dependencies:
+ ansi-regex: "npm:^6.0.1"
+ checksum: 10c0/0d6d7a023de33368fd042aab0bf48f4f4077abdfd60e5393e73c7c411e85e1b3a83507c11af2e656188511475776215df9ca589b4da2295c9455cc399ce1858b
+ languageName: node
+ linkType: hard
+
"strip-bom@npm:^4.0.0":
version: 4.0.0
resolution: "strip-bom@npm:4.0.0"
@@ -13808,6 +14045,17 @@ __metadata:
languageName: node
linkType: hard
+"wrap-ansi@npm:^9.0.0":
+ version: 9.0.2
+ resolution: "wrap-ansi@npm:9.0.2"
+ dependencies:
+ ansi-styles: "npm:^6.2.1"
+ string-width: "npm:^7.0.0"
+ strip-ansi: "npm:^7.1.0"
+ checksum: 10c0/3305839b9a0d6fb930cb63a52f34d3936013d8b0682ff3ec133c9826512620f213800ffa19ea22904876d5b7e9a3c1f40682f03597d986a4ca881fa7b033688c
+ languageName: node
+ linkType: hard
+
"wrappy@npm:1":
version: 1.0.2
resolution: "wrappy@npm:1.0.2"
@@ -13976,6 +14224,15 @@ __metadata:
languageName: node
linkType: hard
+"yaml@npm:^2.8.1":
+ version: 2.8.2
+ resolution: "yaml@npm:2.8.2"
+ bin:
+ yaml: bin.mjs
+ checksum: 10c0/703e4dc1e34b324aa66876d63618dcacb9ed49f7e7fe9b70f1e703645be8d640f68ab84f12b86df8ac960bac37acf5513e115de7c970940617ce0343c8c9cd96
+ languageName: node
+ linkType: hard
+
"yargs-parser@npm:^18.1.2":
version: 18.1.3
resolution: "yargs-parser@npm:18.1.3"