codingpixel-expo-app 0.1.2 → 0.1.4

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.
package/README.md CHANGED
@@ -7,10 +7,13 @@ Opinionated Expo SDK 54+ app scaffolder. Mirrors the [MyRoster](https://github.c
7
7
  ```bash
8
8
  npx codingpixel-expo-app my-app
9
9
  cd my-app
10
- npx expo prebuild
11
- yarn ios # or: npm run ios / yarn android / npm run android
10
+ yarn ios # or: yarn android (npm run ios / npm run android also work)
12
11
  ```
13
12
 
13
+ `yarn ios` / `yarn android` map to `expo run:ios` / `expo run:android` — these BUILD + install the custom dev-client + launch in one shot (3-10 min the first time, fast incremental after). No separate `expo prebuild` step needed.
14
+
15
+ For subsequent runs after the dev-client is installed, use `yarn start` (= `expo start --dev-client`) for faster iteration.
16
+
14
17
  The bin name is `codingpixel-expo` (used after global install). Invoke through `npx codingpixel-expo-app` (the package name) for one-shot runs.
15
18
 
16
19
  ## Not Expo Go-compatible
@@ -23,14 +26,13 @@ This template ships native modules that Expo Go can't load:
23
26
  - `react-native-keyboard-controller`
24
27
  - `@gorhom/bottom-sheet` (when bottom-sheet support enabled)
25
28
 
26
- You **must** prebuild + run a custom dev-client:
29
+ You **must** run a custom dev-client. `yarn ios` / `yarn android` (= `expo run:ios` / `expo run:android`) handle prebuild + native build + dev-client install in one command:
27
30
 
28
31
  ```bash
29
- npx expo prebuild
30
32
  yarn ios # or yarn android / npm run ios / npm run android
31
33
  ```
32
34
 
33
- Subsequent runs use the dev-client + bundler (`yarn start`).
35
+ Subsequent runs use the dev-client + bundler (`yarn start` = `expo start --dev-client`).
34
36
 
35
37
  ## Fonts
36
38
 
@@ -48,12 +50,14 @@ If your generated app's `tsconfig.json` already has a `@/*` mapping, the CLI pre
48
50
 
49
51
  iOS:
50
52
  - Xcode + CocoaPods installed (`sudo gem install cocoapods` if missing).
51
- - `npx expo prebuild` then `yarn ios` (or `npm run ios`) — opens the iOS simulator with your custom dev-client.
53
+ - `yarn ios` (or `npm run ios`) — generates `ios/` dir, runs CocoaPods, builds the dev-client, installs in simulator, launches.
52
54
 
53
55
  Android:
54
56
  - Android SDK + emulator running (or a USB-attached device with debugging enabled).
55
57
  - `JAVA_HOME` pointing at JDK 17.
56
- - `npx expo prebuild` then `yarn android` (or `npm run android`).
58
+ - `yarn android` (or `npm run android`) — generates `android/` dir, builds the dev-client APK, installs, launches.
59
+
60
+ Bundle identifier defaults to `com.<app-name-no-dashes>` (e.g. `com.myapp`). Edit `app.json` `expo.ios.bundleIdentifier` + `expo.android.package` before submitting to App Store / Play Store.
57
61
 
58
62
  ## Expo SDK compatibility
59
63
 
package/dist/index.js CHANGED
@@ -107,10 +107,13 @@ async function main() {
107
107
  log.success(`Project ready at ${target.dir}`);
108
108
  log.raw("");
109
109
  log.raw(` cd ${path.relative(process.cwd(), target.dir) || target.name}`);
110
- log.raw(` npx expo prebuild`);
111
- log.raw(` ${cmdPm} ios # or: ${cmdPm} android`);
110
+ log.raw(` ${cmdPm} ios # one-time: builds + installs custom dev-client + launches`);
111
+ log.raw(` ${cmdPm} android # same for android (needs emulator/device + Android SDK)`);
112
112
  log.raw("");
113
- log.info("First-time dev-client build details: README 'First-time dev-client build'.");
113
+ log.raw(` ${cmdPm} start # subsequent runs: faster connects to installed dev-client`);
114
+ log.raw("");
115
+ log.info("First run takes 3-10 min (native build). After that, `start` is fast. " +
116
+ "iOS needs Xcode + CocoaPods; Android needs SDK + emulator. Not Expo-Go-compatible.");
114
117
  }
115
118
  main().catch((err) => {
116
119
  log.error(err instanceof Error ? err.message : String(err));
package/dist/install.js CHANGED
@@ -43,6 +43,16 @@ export function buildAlwaysInstalledList(workletsPkg) {
43
43
  // resolve 'expo-linking' from .../expo-router/build/views/Unmatched.js").
44
44
  "expo-linking",
45
45
  "expo-constants",
46
+ // Deviation #18 — react-native-mmkv 3.x+ peer deps + system-ui.
47
+ // mmkv was rewritten on Nitro Modules; without `react-native-nitro-modules`,
48
+ // gradle fails with "Project with path ':react-native-nitro-modules' could
49
+ // not be found in project ':react-native-mmkv'" and CocoaPods fails with
50
+ // "Unable to find a specification for `NitroModules` depended upon by `NitroMmkv`".
51
+ "react-native-nitro-modules",
52
+ // expo-system-ui is required by `expo prebuild` for `userInterfaceStyle`
53
+ // in app.json (default value "light"). Without it, prebuild warns:
54
+ // "Install expo-system-ui in your project to enable this feature."
55
+ "expo-system-ui",
46
56
  ];
47
57
  }
48
58
  export function buildConditionalDeps(answers) {
package/dist/patch.js CHANGED
@@ -37,9 +37,9 @@ export function bundleIdSegment(name) {
37
37
  seg = `app${seg}`;
38
38
  return seg || "app";
39
39
  }
40
- /** Compose the full bundle identifier with the `com.codingpixel.` namespace prefix. */
40
+ /** Compose the full bundle identifier `com.<safeName>` (no app-author namespace). */
41
41
  export function bundleIdFor(name) {
42
- return `com.codingpixel.${bundleIdSegment(name)}`;
42
+ return `com.${bundleIdSegment(name)}`;
43
43
  }
44
44
  function readJson(p) {
45
45
  return JSON.parse(fs.readFileSync(p, "utf8"));
@@ -99,6 +99,9 @@ export function patchAppJsonPlugins(target, answers) {
99
99
  "expo-image-picker",
100
100
  {
101
101
  photosPermission: "The app accesses your photos to let you share them with your friends.",
102
+ cameraPermission: "The app accesses your camera to let you take photos to share.",
103
+ // microphone optional — only set if app records video. Add manually:
104
+ // "microphonePermission": "...",
102
105
  },
103
106
  ];
104
107
  if (!json.expo.plugins.some((e) => nameOf(e) === nameOf(entry))) {
@@ -161,17 +164,36 @@ export function patchPackageJsonScripts(target) {
161
164
  const p = path.join(target, "package.json");
162
165
  const pkg = readJson(p);
163
166
  pkg.scripts ??= {};
167
+ // Use `run:android` / `run:ios` so first invocation builds + installs the
168
+ // custom dev-client (we ship `expo-dev-client` + `react-native-mmkv`, both
169
+ // Expo-Go-incompatible). `expo start --android` would error with "No
170
+ // development build for this project is installed" otherwise.
171
+ // `start` uses `--dev-client` so subsequent runs (after first build)
172
+ // connect to the installed client correctly.
164
173
  const want = {
165
- start: "expo start",
166
- android: "expo start --android",
167
- ios: "expo start --ios",
174
+ start: "expo start --dev-client",
175
+ android: "expo run:android",
176
+ ios: "expo run:ios",
168
177
  web: "expo start --web",
169
178
  lint: "expo lint",
179
+ prebuild: "expo prebuild",
170
180
  };
171
181
  for (const [k, v] of Object.entries(want)) {
172
182
  if (!(k in pkg.scripts))
173
183
  pkg.scripts[k] = v;
174
184
  }
185
+ // Force-update if upstream defaults from create-expo-app are present (so
186
+ // existing scaffolds re-running the CLI also get the corrected scripts).
187
+ const stale = {
188
+ "expo start": "expo start --dev-client",
189
+ "expo start --android": "expo run:android",
190
+ "expo start --ios": "expo run:ios",
191
+ };
192
+ for (const [scriptName, current] of Object.entries(pkg.scripts)) {
193
+ if (scriptName in want && stale[current] === want[scriptName]) {
194
+ pkg.scripts[scriptName] = want[scriptName];
195
+ }
196
+ }
175
197
  writeJson(p, pkg);
176
198
  }
177
199
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codingpixel-expo-app",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Opinionated Expo app scaffolder mirroring MyRoster conventions.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,8 @@
1
- import { createMMKV } from "react-native-mmkv";
1
+ // react-native-mmkv 3.x+ exports `MMKV` as a class (was `createMMKV()` factory
2
+ // in older versions). MyRoster's source predates the API change.
3
+ import { MMKV } from "react-native-mmkv";
2
4
 
3
- const storage = createMMKV();
5
+ const storage = new MMKV();
4
6
 
5
7
  export const reduxStorage = {
6
8
  setItem: (key: string, value: string) => {
@@ -12,7 +14,7 @@ export const reduxStorage = {
12
14
  return Promise.resolve(value);
13
15
  },
14
16
  removeItem: (key: string) => {
15
- storage.remove(key);
17
+ storage.delete(key);
16
18
  return Promise.resolve();
17
19
  },
18
20
  };
@@ -1,24 +1,9 @@
1
- import { RF } from '@theme/responsive';
2
- import { ANDROID } from '@utils/constants';
3
- import React, { createContext, useContext } from 'react';
4
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
5
-
6
- const SafeAreaInsetsContext = createContext({});
7
-
8
- export const SafeAreaInsetsProvider = ({ children }: any) => {
9
- let insets = useSafeAreaInsets();
10
- let customInsets = { ...insets };
11
- if (ANDROID) {
12
- customInsets = { ...insets, bottom: insets?.bottom + RF(12) };
13
- }
14
-
15
- return (
16
- <SafeAreaInsetsContext.Provider value={customInsets}>
17
- {children}
18
- </SafeAreaInsetsContext.Provider>
19
- );
20
- };
21
-
22
- export const useSafeArea = () => {
23
- return useContext(SafeAreaInsetsContext);
24
- };
1
+ // V5 plan dropped MyRoster's `SafeAreaInsetsProvider` (Android-padding tweak)
2
+ // from `_layout.tsx` relying on stock `react-native-safe-area-context` is
3
+ // cleaner and avoids a context that was never wrapped around the tree.
4
+ //
5
+ // `useSafeArea` is preserved as a thin re-export so existing component code
6
+ // (AppWrapper, AppButton, etc.) keeps compiling without edits.
7
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
8
+
9
+ export const useSafeArea = useSafeAreaInsets;