diff --git a/.changeset/poor-lamps-share.md b/.changeset/poor-lamps-share.md new file mode 100644 index 00000000..a845151c --- /dev/null +++ b/.changeset/poor-lamps-share.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..b0525afe --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,19 @@ +# Project instructions + +## Changesets + +This repo uses [changesets](https://github.com/changesets/changesets), and a +changeset-bot check runs on every PR. + +- If a PR changes a **published package** (anything under `modules/`), add a + changeset describing the change and its semver bump (`npx changeset`). +- If a PR's changes are confined to **non-published workspaces** (e.g. the + `example-app` in `apps/`, docs, CI config), no version bump is needed — but + the changeset check still requires a changeset to be present. In that case add + an **empty changeset** so the check passes without bumping any package: + + ```sh + npx changeset --empty + ``` + + Commit the generated `.changeset/*.md` file along with the PR. diff --git a/apps/ExampleApp/app/screens/HomeScreen/HomeScreen.tsx b/apps/ExampleApp/app/screens/HomeScreen/HomeScreen.tsx index 683dd4f9..27675876 100644 --- a/apps/ExampleApp/app/screens/HomeScreen/HomeScreen.tsx +++ b/apps/ExampleApp/app/screens/HomeScreen/HomeScreen.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react-lite" import { ViewStyle, FlatList, View } from "react-native" import { NativeStackScreenProps } from "@react-navigation/native-stack" import { AppStackScreenProps } from "app/navigators" -import { Text } from "app/components" +import { Screen, Text } from "app/components" import { DEMO_LIST, DemoInfo } from "./demoInfo" import { DemoListItem } from "./components/DemoListItem" import { useTypedNavigation } from "../../navigators/useTypedNavigation" @@ -27,22 +27,37 @@ export const HomeScreen: FC = observer(function HomeScreen() { [navigation], ) + // Use a "fixed" preset so the FlatList does its own scrolling — a + // VirtualizedList must not be nested inside the ScrollView that the + // "scroll" preset would provide. return ( - - - + + + + + - - } - data={DEMO_LIST} - renderItem={renderItem} - contentContainerStyle={$contentContainerStyle} - /> + } + data={DEMO_LIST} + renderItem={renderItem} + style={$list} + contentContainerStyle={$contentContainerStyle} + /> + ) }) +// Let the inner container fill the screen so the FlatList can size itself. +const $screenContentContainer: ViewStyle = { flex: 1 } + +const $list: ViewStyle = { flex: 1 } + const $shadowSpace: ViewStyle = { paddingBottom: 4, backgroundColor: "rgba(0,0,0,0)", diff --git a/apps/ExampleApp/app/utils/useExampleImage/useExampleImage.ts b/apps/ExampleApp/app/utils/useExampleImage/useExampleImage.ts index 10e2c79e..ba6c770a 100644 --- a/apps/ExampleApp/app/utils/useExampleImage/useExampleImage.ts +++ b/apps/ExampleApp/app/utils/useExampleImage/useExampleImage.ts @@ -5,6 +5,7 @@ import { ImagePickerOptions, ImagePickerAsset, useCameraPermissions, + UIImagePickerPresentationStyle, } from "expo-image-picker" import { useCallback, useState, useMemo } from "react" import { useAssets, Asset } from "expo-asset" @@ -61,6 +62,20 @@ const IMAGE_PICKER_OPTIONS: ImagePickerOptions = { quality: 0.5, } +// The photo library picker presents as a card sheet (iOS) instead of the +// default full-screen presentation, whose nav bar renders under the status +// bar / Dynamic Island. +const LIBRARY_PICKER_OPTIONS: ImagePickerOptions = { + ...IMAGE_PICKER_OPTIONS, + presentationStyle: UIImagePickerPresentationStyle.PAGE_SHEET, +} + +// The camera stays full-screen, which is the conventional capture experience. +const CAMERA_PICKER_OPTIONS: ImagePickerOptions = { + ...IMAGE_PICKER_OPTIONS, + presentationStyle: UIImagePickerPresentationStyle.FULL_SCREEN, +} + export function useExampleImage(predicates?: { filter?: ImageFilter groupBy?: ImageGrouper @@ -110,7 +125,7 @@ export function useExampleImage(predicates?: { const selectPhoto = useCallback(async () => { setStatus("selectingPhoto") - const result: ImagePickerResult = await launchImageLibraryAsync(IMAGE_PICKER_OPTIONS) + const result: ImagePickerResult = await launchImageLibraryAsync(LIBRARY_PICKER_OPTIONS) if (result.assets?.[0]) { setImage({ ...result.assets?.[0], localUri: result.assets?.[0].uri } as SelectedImage) } else { @@ -127,7 +142,7 @@ export function useExampleImage(predicates?: { return } setStatus("takingPhoto") - const result: ImagePickerResult = await launchCameraAsync(IMAGE_PICKER_OPTIONS) + const result: ImagePickerResult = await launchCameraAsync(CAMERA_PICKER_OPTIONS) if (result.assets?.[0]) { setImage({ ...result.assets?.[0], localUri: result.assets?.[0].uri } as SelectedImage) } else {