create-react-native-library-template 0.1.0

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.
Files changed (39) hide show
  1. package/README.md +27 -0
  2. package/index.mjs +62 -0
  3. package/package.json +41 -0
  4. package/template/.changeset/README.md +7 -0
  5. package/template/.changeset/config.json +11 -0
  6. package/template/.github/workflows/ci.yml +42 -0
  7. package/template/.github/workflows/release.yml +46 -0
  8. package/template/AGENTS.md +97 -0
  9. package/template/CLAUDE.md +5 -0
  10. package/template/README.md +67 -0
  11. package/template/apps/native/.rnstorybook/index.tsx +11 -0
  12. package/template/apps/native/.rnstorybook/main.ts +12 -0
  13. package/template/apps/native/.rnstorybook/preview.tsx +24 -0
  14. package/template/apps/native/app.json +17 -0
  15. package/template/apps/native/babel.config.js +8 -0
  16. package/template/apps/native/index.ts +5 -0
  17. package/template/apps/native/metro.config.js +18 -0
  18. package/template/apps/native/package.json +40 -0
  19. package/template/apps/native/tsconfig.json +8 -0
  20. package/template/apps/storybook/.storybook/main.ts +12 -0
  21. package/template/apps/storybook/.storybook/preview.tsx +14 -0
  22. package/template/apps/storybook/.storybook/vitest.setup.ts +7 -0
  23. package/template/apps/storybook/package.json +33 -0
  24. package/template/apps/storybook/tsconfig.json +7 -0
  25. package/template/apps/storybook/vitest.config.ts +25 -0
  26. package/template/biome.json +9 -0
  27. package/template/bun.lock +2479 -0
  28. package/template/gitignore +23 -0
  29. package/template/package.json +33 -0
  30. package/template/packages/ui/package.json +81 -0
  31. package/template/packages/ui/src/components/Button/button.stories.tsx +79 -0
  32. package/template/packages/ui/src/components/Button/button.test.tsx +33 -0
  33. package/template/packages/ui/src/components/Button/button.tsx +128 -0
  34. package/template/packages/ui/src/theme/tokens.ts +40 -0
  35. package/template/packages/ui/tsconfig.build.json +13 -0
  36. package/template/packages/ui/tsconfig.json +7 -0
  37. package/template/packages/ui/vitest.config.ts +16 -0
  38. package/template/packages/ui/vitest.setup.ts +1 -0
  39. package/template/tsconfig.base.json +20 -0
package/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # create-react-native-library-template
2
+
3
+ Scaffold a publishable React Native UI library monorepo in one command:
4
+
5
+ ```sh
6
+ bun create react-native-library-template my-library
7
+ # or: npm create react-native-library-template@latest my-library
8
+ ```
9
+
10
+ ## What you get
11
+
12
+ - **Bun workspaces** monorepo: the library (`packages/ui`), a web Storybook (`apps/storybook`), and an Expo app running Storybook on device (`apps/native`).
13
+ - **Storybook 10** on web (react-native-web + Vite) and native, sharing the same CSF3 stories.
14
+ - **Vitest** unit tests (jsdom + react-native-web) and story tests (browser mode, `play` functions).
15
+ - **Biome** linting/formatting, **TypeScript** strict mode.
16
+ - **react-native-builder-bob** library build, **Changesets** versioning/publishing, GitHub Actions CI + release workflows.
17
+
18
+ After scaffolding:
19
+
20
+ ```sh
21
+ cd my-library
22
+ bun install
23
+ git init && git add -A && git commit -m "Initial commit"
24
+ bun run storybook
25
+ ```
26
+
27
+ See the generated `AGENTS.md` for the full development guide, including the checklist for adding new components. Source: [iv-stpn/react-native-library-template](https://github.com/iv-stpn/react-native-library-template).
package/index.mjs ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ import { cpSync, existsSync, readdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
3
+ import { basename, dirname, join, resolve } from 'node:path';
4
+ import process from 'node:process';
5
+ import { createInterface } from 'node:readline/promises';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const templateDir = join(dirname(fileURLToPath(import.meta.url)), 'template');
9
+ const defaultName = 'my-react-native-library';
10
+
11
+ async function resolveTarget() {
12
+ const argument = process.argv[2];
13
+ if (argument) return argument;
14
+ const readline = createInterface({ input: process.stdin, output: process.stdout });
15
+ const answer = (await readline.question(`Project directory (${defaultName}): `)).trim();
16
+ readline.close();
17
+ return answer || defaultName;
18
+ }
19
+
20
+ function restoreGitignores(directory) {
21
+ for (const entry of readdirSync(directory, { withFileTypes: true })) {
22
+ const entryPath = join(directory, entry.name);
23
+ if (entry.isDirectory()) restoreGitignores(entryPath);
24
+ else if (entry.name === 'gitignore') renameSync(entryPath, join(directory, '.gitignore'));
25
+ }
26
+ }
27
+
28
+ const target = await resolveTarget();
29
+ const targetDir = resolve(process.cwd(), target);
30
+ const projectName =
31
+ basename(targetDir)
32
+ .toLowerCase()
33
+ .replace(/[^a-z0-9-_.~]+/g, '-')
34
+ .replace(/^[-_.]+|[-_.]+$/g, '') || defaultName;
35
+
36
+ if (existsSync(targetDir) && readdirSync(targetDir).length > 0) {
37
+ console.error(`Error: ${targetDir} already exists and is not empty.`);
38
+ process.exit(1);
39
+ }
40
+
41
+ cpSync(templateDir, targetDir, { recursive: true });
42
+ restoreGitignores(targetDir);
43
+
44
+ const packageJsonPath = join(targetDir, 'package.json');
45
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
46
+ packageJson.name = projectName;
47
+ writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`);
48
+
49
+ console.log(`
50
+ Scaffolded ${projectName} in ${targetDir}
51
+
52
+ Next steps:
53
+ cd ${target}
54
+ bun install
55
+ git init && git add -A && git commit -m "Initial commit"
56
+
57
+ Useful commands:
58
+ bun run storybook # web Storybook at http://localhost:6006
59
+ bun run storybook:native # Expo dev server for on-device Storybook
60
+ bun run test # unit + Storybook tests
61
+ See AGENTS.md for the full guide (rename the @template/* packages to your own scope).
62
+ `);
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "create-react-native-library-template",
3
+ "version": "0.1.0",
4
+ "description": "Scaffold a React Native UI library monorepo: Bun workspaces, Expo, Storybook (web + native), Vitest, Biome and Changesets",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "create-react-native-library-template": "index.mjs"
9
+ },
10
+ "files": [
11
+ "index.mjs",
12
+ "template"
13
+ ],
14
+ "scripts": {
15
+ "prepack": "node scripts/prepare-template.mjs",
16
+ "postpack": "node -e \"require('node:fs').rmSync('template', { recursive: true, force: true })\""
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/iv-stpn/react-native-library-template.git",
21
+ "directory": "create"
22
+ },
23
+ "homepage": "https://github.com/iv-stpn/react-native-library-template#readme",
24
+ "keywords": [
25
+ "react-native",
26
+ "template",
27
+ "create",
28
+ "scaffold",
29
+ "ui",
30
+ "component-library",
31
+ "storybook",
32
+ "expo",
33
+ "bun"
34
+ ],
35
+ "engines": {
36
+ "node": ">=18"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ }
41
+ }
@@ -0,0 +1,7 @@
1
+ # Changesets
2
+
3
+ This folder is managed by [changesets](https://github.com/changesets/changesets).
4
+
5
+ Run `bun run changeset` after any user-facing change to `@template/ui`, pick a bump
6
+ type (patch/minor/major), and describe the change. The release workflow turns
7
+ accumulated changesets into a "Version Packages" PR; merging that PR publishes to npm.
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
3
+ "changelog": "@changesets/cli/changelog",
4
+ "commit": false,
5
+ "fixed": [],
6
+ "linked": [],
7
+ "access": "public",
8
+ "baseBranch": "main",
9
+ "updateInternalDependencies": "patch",
10
+ "ignore": ["@template/storybook-web", "@template/example"]
11
+ }
@@ -0,0 +1,42 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ci-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ jobs:
13
+ checks:
14
+ name: Lint, typecheck, test, build
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: oven-sh/setup-bun@v2
20
+ with:
21
+ bun-version: latest
22
+
23
+ - name: Install dependencies
24
+ run: bun install --frozen-lockfile
25
+
26
+ - name: Lint (biome)
27
+ run: bun run lint
28
+
29
+ - name: Typecheck
30
+ run: bun run typecheck
31
+
32
+ - name: Unit tests (vitest)
33
+ run: bun run test:unit
34
+
35
+ - name: Build library
36
+ run: bun run build
37
+
38
+ - name: Install Playwright browsers
39
+ run: bunx playwright install --with-deps chromium
40
+
41
+ - name: Storybook tests (vitest browser mode)
42
+ run: bun run test:storybook
@@ -0,0 +1,46 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ concurrency: release-${{ github.ref }}
8
+
9
+ permissions:
10
+ contents: write
11
+ pull-requests: write
12
+ id-token: write
13
+
14
+ jobs:
15
+ release:
16
+ name: Version or publish
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ with:
21
+ fetch-depth: 0
22
+
23
+ - uses: oven-sh/setup-bun@v2
24
+ with:
25
+ bun-version: latest
26
+
27
+ # `changeset publish` shells out to npm, which needs Node and registry auth.
28
+ - uses: actions/setup-node@v4
29
+ with:
30
+ node-version: 22
31
+ registry-url: https://registry.npmjs.org
32
+
33
+ - name: Install dependencies
34
+ run: bun install --frozen-lockfile
35
+
36
+ - name: Create release PR or publish to npm
37
+ uses: changesets/action@v1
38
+ with:
39
+ version: bun run version-packages
40
+ publish: bun run release
41
+ commit: 'chore: version packages'
42
+ title: 'chore: version packages'
43
+ env:
44
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
45
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
46
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,97 @@
1
+ # Agent guide
2
+
3
+ Monorepo for a publishable React Native UI library. Bun workspaces:
4
+
5
+ | Workspace | Package | Purpose |
6
+ | --- | --- | --- |
7
+ | `packages/ui` | `@template/ui` | The library. The only published package. |
8
+ | `apps/storybook` | `@template/storybook-web` | Web Storybook (react-native-web + Vite) and Storybook tests (Vitest browser mode). |
9
+ | `apps/native` | `@template/example` | Expo app running Storybook React Native on device. |
10
+
11
+ Tooling: **bun** (package manager + script runner), **biome** (lint + format), **TypeScript 6**
12
+ (strict, `verbatimModuleSyntax` — use `import type` for types), **vitest** (unit tests via
13
+ react-native-web in jsdom; story tests via `@storybook/addon-vitest` in Chromium),
14
+ **react-native-builder-bob** (library build), **changesets** (versioning/publishing).
15
+
16
+ ## Commands (run from the repo root)
17
+
18
+ | Command | What it does |
19
+ | --- | --- |
20
+ | `bun install` | Install all workspaces. |
21
+ | `bun run lint` / `bun run lint:fix` | Biome check / autofix. |
22
+ | `bun run typecheck` | `tsc --noEmit` in every workspace. |
23
+ | `bun run test:unit` | Vitest unit tests in `packages/ui`. |
24
+ | `bun run test:storybook` | Runs every story as a Vitest browser test (needs `bunx playwright install chromium` once). |
25
+ | `bun run test` | Both of the above. |
26
+ | `bun run build` | Builds the library with bob into `packages/ui/lib`. |
27
+ | `bun run storybook` | Web Storybook at http://localhost:6006. |
28
+ | `bun run storybook:native` | Expo dev server for the on-device Storybook. |
29
+ | `bun run changeset` | Record a changeset for release notes/versioning. |
30
+
31
+ ## Creating a new component
32
+
33
+ Follow the `Button` component (`packages/ui/src/components/Button/`) as the reference
34
+ implementation. For a component named `Foo`:
35
+
36
+ 1. **Create the folder** `packages/ui/src/components/Foo/` containing exactly:
37
+ - `Foo.tsx` — the component.
38
+ - `Foo.test.tsx` — vitest unit tests.
39
+ - `Foo.stories.tsx` — Storybook stories (CSF3), including at least one `play` function.
40
+ - `index.ts` — re-exports: `export { Foo, type FooProps } from './Foo';`
41
+ 2. **Write the component** (`Foo.tsx`):
42
+ - Named function export (`export function Foo(...)`), never a default export.
43
+ - Export a `FooProps` interface with a JSDoc comment per prop; document defaults with `@default`.
44
+ - Only import from `react`, `react-native`, and internal modules. New runtime dependencies
45
+ need explicit approval — they become dependencies for every consumer of the library.
46
+ - Use only RN APIs that exist on react-native-web (`View`, `Text`, `Pressable`,
47
+ `StyleSheet`, ...), otherwise unit tests and the web Storybook will break.
48
+ - Style with `StyleSheet.create` and the design tokens from `src/theme` (`colors`,
49
+ `spacing`, `radii`, `fontSizes`) — no hard-coded colors or magic numbers. Add new tokens
50
+ to `src/theme/tokens.ts` if needed.
51
+ - Accessibility is required: set `accessibilityRole`, `accessibilityState`, and accept an
52
+ `accessibilityLabel` prop. Also accept `style` (as `StyleProp<...>`) and `testID`.
53
+ 3. **Export it from the library**: add `export * from './components/Foo';` to
54
+ `packages/ui/src/index.ts`.
55
+ 4. **Write stories** (`Foo.stories.tsx`):
56
+ - CSF3 with `satisfies Meta<typeof Foo>` and `StoryObj<typeof meta>`; title `Components/Foo`.
57
+ - Set default `args` for every prop; use `fn()` from `storybook/test` for callbacks.
58
+ - One story per visual variant/state, plus interaction stories with `play` functions
59
+ asserting behavior (`within`, `userEvent`, `expect` from `storybook/test`).
60
+ - Stories are shared by the web and native Storybooks — keep them platform-neutral and
61
+ import types only from `@storybook/react` (type-only imports are erased at runtime).
62
+ 5. **Write unit tests** (`Foo.test.tsx`) with `@testing-library/react`. They run in jsdom with
63
+ `react-native` aliased to `react-native-web`. Query by accessible role/name
64
+ (`screen.getByRole('button', { name: ... })`), and cover: rendering, interaction callbacks,
65
+ and disabled/edge states.
66
+ 6. **Verify** from the repo root — all must pass:
67
+ ```sh
68
+ bun run lint && bun run typecheck && bun run test:unit && bun run build && bun run test:storybook
69
+ ```
70
+ 7. **Add a changeset**: `bun run changeset` → select `@template/ui`, pick `minor` for a new
71
+ component (`patch` for fixes, `major` for breaking changes), write a one-line summary.
72
+ Commit the generated `.changeset/*.md` file with your change.
73
+
74
+ ## Releasing
75
+
76
+ CI (`.github/workflows/ci.yml`) runs lint, typecheck, tests, build, and Storybook tests on
77
+ every PR. On pushes to `main`, `.github/workflows/release.yml` uses changesets to open/update
78
+ a "Version Packages" PR; merging it publishes `@template/ui` to npm (requires the `NPM_TOKEN`
79
+ repository secret). Never edit versions in `package.json` or `CHANGELOG.md` by hand.
80
+
81
+ ## Gotchas
82
+
83
+ - `apps/native/.rnstorybook/storybook.requires.ts` is generated (by Metro or
84
+ `bun run --cwd apps/native storybook-generate`) and gitignored — never edit it.
85
+ - Test/story files are excluded from the published package and from the bob build; keep
86
+ runtime code out of them.
87
+ - The example app must stay on Expo SDK-pinned dependency versions (`bunx expo install ...`
88
+ from `apps/native` when adding native modules).
89
+
90
+ ## Scaffolder (`create/`)
91
+
92
+ `create/` holds `create-react-native-library-template`, the npm package behind
93
+ `bun create react-native-library-template`. It is **not** a workspace and is not managed by
94
+ changesets: it has zero dependencies and is published manually. Its `prepack` script snapshots
95
+ every tracked file of this repo (except `create/` itself) into `create/template/` (renaming
96
+ `.gitignore` → `gitignore`, which the CLI reverses on scaffold); `postpack` deletes the
97
+ snapshot. To release it: bump `create/package.json` version, then `cd create && npm publish`.
@@ -0,0 +1,5 @@
1
+ # CLAUDE.md
2
+
3
+ All repository guidance lives in [AGENTS.md](./AGENTS.md). Read and follow it — in particular
4
+ the "Creating a new component" checklist and the requirement to add a changeset with every
5
+ user-facing change.
@@ -0,0 +1,67 @@
1
+ # react-native-library-template
2
+
3
+ Template for building and publishing a React Native UI component library.
4
+
5
+ - **[Bun](https://bun.sh)** — package manager, script runner, workspaces
6
+ - **[TypeScript 6](https://www.typescriptlang.org)** — strict mode everywhere
7
+ - **[Biome](https://biomejs.dev)** — linting + formatting
8
+ - **[Vitest](https://vitest.dev)** — unit tests (react-native-web in jsdom)
9
+ - **[Storybook 10](https://storybook.js.org)** — web (react-native-web + Vite) **and** on-device (Expo) demos from the same stories
10
+ - **Storybook tests** — every story runs as a Vitest browser-mode test; `play` functions assert interactions
11
+ - **[Changesets](https://github.com/changesets/changesets)** — versioning, changelogs, npm publishing via GitHub Actions
12
+ - **[react-native-builder-bob](https://github.com/callstack/react-native-builder-bob)** — ESM + type declarations build
13
+
14
+ ## Layout
15
+
16
+ ```
17
+ packages/ui/ @template/ui — the library (published)
18
+ apps/storybook/ Web Storybook + Storybook tests
19
+ apps/native/ Expo app running Storybook React Native on device
20
+ ```
21
+
22
+ ## Getting started
23
+
24
+ Scaffold a fresh project from this template:
25
+
26
+ ```sh
27
+ bun create react-native-library-template my-library
28
+ # or: npm create react-native-library-template@latest my-library
29
+ ```
30
+
31
+ Or work in a clone of this repo directly:
32
+
33
+ ```sh
34
+ bun install
35
+
36
+ bun run storybook # web Storybook → http://localhost:6006
37
+ bun run storybook:native # Expo dev server (press i / a, or scan QR)
38
+
39
+ bun run lint # biome
40
+ bun run typecheck # tsc in every workspace
41
+ bun run test:unit # vitest unit tests
42
+ bunx playwright install chromium # once, for storybook tests
43
+ bun run test:storybook # every story as a browser test
44
+ bun run build # library build → packages/ui/lib
45
+ ```
46
+
47
+ ## Adding components
48
+
49
+ See [AGENTS.md](./AGENTS.md) — it documents the full checklist (component, tests, stories,
50
+ exports, changeset). `packages/ui/src/components/Button` is the reference implementation.
51
+
52
+ ## Releasing
53
+
54
+ 1. With every user-facing change, run `bun run changeset` and commit the generated file.
55
+ 2. On merge to `main`, the release workflow opens/updates a **Version Packages** PR.
56
+ 3. Merge that PR → `@template/ui` is built and published to npm.
57
+
58
+ Requires an `NPM_TOKEN` repository secret (npm automation token) and workflow permission to
59
+ create pull requests (repo Settings → Actions → General → "Allow GitHub Actions to create and
60
+ approve pull requests").
61
+
62
+ ## Using this template
63
+
64
+ 1. Rename `@template/ui` in `packages/ui/package.json` (plus its uses in the two app
65
+ `package.json`s, `.changeset/config.json`, root scripts, and AGENTS.md) to your package name.
66
+ 2. Update `repository`, `license`, and `description` in `packages/ui/package.json`.
67
+ 3. Push to GitHub, add the `NPM_TOKEN` secret, and start building components.
@@ -0,0 +1,11 @@
1
+ import AsyncStorage from '@react-native-async-storage/async-storage';
2
+ import { view } from './storybook.requires';
3
+
4
+ const StorybookUIRoot = view.getStorybookUI({
5
+ storage: {
6
+ getItem: AsyncStorage.getItem,
7
+ setItem: AsyncStorage.setItem,
8
+ },
9
+ });
10
+
11
+ export default StorybookUIRoot;
@@ -0,0 +1,12 @@
1
+ import type { StorybookConfig } from '@storybook/react-native';
2
+
3
+ const main: StorybookConfig = {
4
+ stories: ['../../../packages/ui/src/**/*.stories.@(ts|tsx)'],
5
+ deviceAddons: [
6
+ '@storybook/addon-ondevice-controls',
7
+ '@storybook/addon-ondevice-actions',
8
+ '@storybook/addon-ondevice-backgrounds',
9
+ ],
10
+ };
11
+
12
+ export default main;
@@ -0,0 +1,24 @@
1
+ import type { Preview } from '@storybook/react';
2
+ import { View } from 'react-native';
3
+
4
+ const preview: Preview = {
5
+ decorators: [
6
+ (Story) => (
7
+ // biome-ignore lint/plugin: exception for storybook preview
8
+ <View style={{ flex: 1, alignItems: 'flex-start', padding: 16 }}>
9
+ <Story />
10
+ </View>
11
+ ),
12
+ ],
13
+ parameters: {
14
+ backgrounds: {
15
+ default: 'plain',
16
+ values: [
17
+ { name: 'plain', value: '#ffffff' },
18
+ { name: 'dark', value: '#18181b' },
19
+ ],
20
+ },
21
+ },
22
+ };
23
+
24
+ export default preview;
@@ -0,0 +1,17 @@
1
+ {
2
+ "expo": {
3
+ "name": "UI Library Example",
4
+ "slug": "ui-library-example",
5
+ "version": "1.0.0",
6
+ "orientation": "portrait",
7
+ "userInterfaceStyle": "automatic",
8
+ "newArchEnabled": true,
9
+ "ios": {
10
+ "supportsTablet": true
11
+ },
12
+ "android": {
13
+ "edgeToEdgeEnabled": true
14
+ },
15
+ "plugins": ["@react-native-community/datetimepicker"]
16
+ }
17
+ }
@@ -0,0 +1,8 @@
1
+ /** biome-ignore-all lint/style/noCommonJs: exception for babel config */
2
+ module.exports = (api) => {
3
+ api.cache(true);
4
+ return {
5
+ presets: ['babel-preset-expo'],
6
+ plugins: ['react-native-worklets/plugin'],
7
+ };
8
+ };
@@ -0,0 +1,5 @@
1
+ import 'react-native-gesture-handler';
2
+ import { registerRootComponent } from 'expo';
3
+ import StorybookUIRoot from './.rnstorybook';
4
+
5
+ registerRootComponent(StorybookUIRoot);
@@ -0,0 +1,18 @@
1
+ /** biome-ignore-all lint/style/noCommonJs: exception for metro config */
2
+ const path = require('node:path');
3
+ const { withStorybook } = require('@storybook/react-native/metro/withStorybook');
4
+ const { getDefaultConfig } = require('expo/metro-config');
5
+
6
+ const projectRoot = import.meta.dirname;
7
+ const workspaceRoot = path.resolve(projectRoot, '../..');
8
+
9
+ const config = getDefaultConfig(projectRoot);
10
+
11
+ // Monorepo: watch the whole workspace and resolve hoisted dependencies.
12
+ config.watchFolders = [workspaceRoot];
13
+ config.resolver.nodeModulesPaths = [path.resolve(projectRoot, 'node_modules'), path.resolve(workspaceRoot, 'node_modules')];
14
+
15
+ module.exports = withStorybook(config, {
16
+ enabled: true,
17
+ configPath: path.resolve(projectRoot, '.rnstorybook'),
18
+ });
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@template/example",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "main": "index.ts",
6
+ "scripts": {
7
+ "start": "expo start --tunnel",
8
+ "android": "expo start --android",
9
+ "ios": "expo start --ios",
10
+ "storybook-generate": "sb-rn-get-stories",
11
+ "typecheck": "bun run storybook-generate && tsc --noEmit"
12
+ },
13
+ "dependencies": {
14
+ "@gorhom/bottom-sheet": "^5.2.14",
15
+ "@react-native-async-storage/async-storage": "2.2.0",
16
+ "@react-native-community/datetimepicker": "8.4.4",
17
+ "@react-native-community/slider": "5.0.1",
18
+ "@storybook/addon-ondevice-actions": "^10.4.6",
19
+ "@storybook/addon-ondevice-backgrounds": "^10.4.6",
20
+ "@storybook/addon-ondevice-controls": "^10.4.6",
21
+ "@storybook/react": "^10.4.6",
22
+ "@storybook/react-native": "^10.4.6",
23
+ "@template/ui": "workspace:*",
24
+ "expo": "^54",
25
+ "expo-status-bar": "3.0.9",
26
+ "react": "19.1.0",
27
+ "react-native": "0.81.5",
28
+ "react-native-gesture-handler": "2.28.0",
29
+ "react-native-reanimated": "4.1.1",
30
+ "react-native-safe-area-context": "5.6.0",
31
+ "react-native-svg": "15.12.1",
32
+ "react-native-worklets": "0.5.1",
33
+ "storybook": "^10.4.6"
34
+ },
35
+ "devDependencies": {
36
+ "@types/react": "~19.1.10",
37
+ "babel-preset-expo": "~54.0.10",
38
+ "typescript": "^6"
39
+ }
40
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "lib": ["ES2023"]
5
+ },
6
+ "include": ["**/*.ts", "**/*.tsx"],
7
+ "exclude": ["node_modules"]
8
+ }
@@ -0,0 +1,12 @@
1
+ import type { StorybookConfig } from '@storybook/react-native-web-vite';
2
+
3
+ const config: StorybookConfig = {
4
+ stories: ['../../../packages/ui/src/**/*.stories.@(ts|tsx)'],
5
+ addons: ['@storybook/addon-docs', '@storybook/addon-vitest'],
6
+ framework: {
7
+ name: '@storybook/react-native-web-vite',
8
+ options: {},
9
+ },
10
+ };
11
+
12
+ export default config;
@@ -0,0 +1,14 @@
1
+ import type { Preview } from '@storybook/react';
2
+
3
+ const preview: Preview = {
4
+ parameters: {
5
+ controls: {
6
+ matchers: {
7
+ color: /(background|color)$/i,
8
+ date: /Date$/i,
9
+ },
10
+ },
11
+ },
12
+ };
13
+
14
+ export default preview;
@@ -0,0 +1,7 @@
1
+ import { setProjectAnnotations } from '@storybook/react-native-web-vite';
2
+ import { beforeAll } from 'vitest';
3
+ import preview from './preview';
4
+
5
+ const annotations = setProjectAnnotations([preview]);
6
+
7
+ beforeAll(annotations.beforeAll);
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@template/storybook-web",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "storybook": "storybook dev -p 6006",
7
+ "build-storybook": "storybook build",
8
+ "typecheck": "tsc --noEmit",
9
+ "test": "vitest run",
10
+ "test:watch": "vitest"
11
+ },
12
+ "dependencies": {
13
+ "@template/ui": "workspace:*",
14
+ "react": "19.1.0",
15
+ "react-dom": "19.1.0",
16
+ "react-native": "0.81.5",
17
+ "react-native-web": "0.21.2"
18
+ },
19
+ "devDependencies": {
20
+ "@storybook/addon-docs": "^10.4.6",
21
+ "@storybook/addon-vitest": "^10.4.6",
22
+ "@storybook/react": "^10.4.6",
23
+ "@storybook/react-native-web-vite": "^10.4.6",
24
+ "@types/node": "^26",
25
+ "@types/react": "~19.1.10",
26
+ "@vitest/browser-playwright": "^4.1.10",
27
+ "playwright": "^1.61.1",
28
+ "storybook": "^10.4.6",
29
+ "typescript": "^6",
30
+ "vite": "^8.1.3",
31
+ "vitest": "^4.1.10"
32
+ }
33
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "lib": ["ES2023", "DOM", "DOM.Iterable"]
5
+ },
6
+ "include": [".storybook", "vitest.config.ts"]
7
+ }