Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "docs",
"version": "10.2.2-alpha.5",
"version": "10.2.2-canary.1",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
Expand Down
4 changes: 4 additions & 0 deletions examples/expo-example/.rnstorybook/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import { view } from './storybook.requires';
const isScreenshotTesting = process.env.EXPO_PUBLIC_SCREENSHOT_TESTING === 'true';
const isLiteUI = process.env.EXPO_PUBLIC_LITE_UI === 'true';

export const showStorybook = (v: boolean = true) => {
view.showStorybook(v);
};

const StorybookUIRoot = view.getStorybookUI({
shouldPersistSelection: true,
storage: {
Expand Down
4 changes: 3 additions & 1 deletion examples/expo-example/.rnstorybook/storybook.requires.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ declare global {
var view: View;
var STORIES: typeof normalizedStories;
var STORYBOOK_WEBSOCKET: { host: string; port: number } | undefined;
var STORYBOOK_FORCE_OPEN: boolean | undefined;
}


Expand All @@ -62,8 +63,9 @@ const annotations = [
require('./local-addon-example/preview')
];


globalThis.STORIES = normalizedStories;
globalThis.STORYBOOK_WEBSOCKET = { host: '192.168.1.172', port: 7007 };
globalThis.STORYBOOK_WEBSOCKET = { host: '192.168.86.20', port: 7007 };

// @ts-ignore
module?.hot?.accept?.();
Expand Down
14 changes: 13 additions & 1 deletion examples/expo-example/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
// fixes fast refresh on web
import '@expo/metro-runtime';

export { default } from './.rnstorybook';
import SBRoot, { showStorybook } from './.rnstorybook';
import { Button, View, Text } from 'react-native';

export default function App() {
return (
<SBRoot>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>This is the user&apos;s app</Text>
<Button title="Show Storybook" onPress={() => showStorybook(true)} />
</View>
</SBRoot>
);
}
6 changes: 4 additions & 2 deletions examples/expo-example/metro.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const path = require('node:path');

// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require('expo/metro-config');
const path = require('path');

const projectRoot = __dirname;
const workspaceRoot = path.resolve(projectRoot, '../../');
Expand All @@ -22,6 +23,7 @@ defaultConfig.resolver.nodeModulesPaths = [

const { withStorybook } = require('@storybook/react-native/metro/withStorybook');
const { withRozenite } = require('@rozenite/metro');

module.exports = withRozenite(
withStorybook(defaultConfig, {
enabled: process.env.EXPO_PUBLIC_STORYBOOK_ENABLED === 'true',
Expand All @@ -35,7 +37,7 @@ module.exports = withRozenite(
);

/* , {
enabled: process.env.STORYBOOK_ENABLED === 'true',
enabled: process.env.STORYBOOK_FORCE_ENABLED === 'true',
configPath: path.resolve(__dirname, './.rnstorybook'),
// websockets: {
// port: 7007,
Expand Down
13 changes: 11 additions & 2 deletions examples/expo-example/package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
{
"name": "expo-example",
"version": "10.2.2-alpha.5",
"version": "10.2.2-canary.1",
"private": true,
"main": "index.js",
"scripts": {
"android": "EXPO_PUBLIC_STORYBOOK_ENABLED=true expo start --android",
"ios": "EXPO_PUBLIC_STORYBOOK_ENABLED=true expo start --ios",
"web": "EXPO_PUBLIC_STORYBOOK_ENABLED=true expo start --web",
"storybook:disabled": "expo start",
"storybook:normal": "EXPO_PUBLIC_STORYBOOK_ENABLED=true expo start",
"storybook:capture": "STORYBOOK_FORCE_ENABLED=true STORYBOOK_FORCE_OPEN=true STORYBOOK_CHANNEL_PORT=6006 STORYBOOK_CHANNEL_HOST=http://localhost expo start",
"storybook": "EXPO_PUBLIC_STORYBOOK_ENABLED=true expo start",
"storybook:lite": "EXPO_PUBLIC_STORYBOOK_ENABLED=true EXPO_PUBLIC_LITE_UI=true expo start -c",
"storybook:test": "EXPO_PUBLIC_SCREENSHOT_TESTING=true EXPO_PUBLIC_STORYBOOK_ENABLED=true expo start -c",
Expand All @@ -21,7 +24,7 @@
"test": "jest",
"test:ci": "jest --runInBand",
"test:screenshots": "screenshot-stories --ignore-regions '376,2512,428,24' --html-report",
"eas-build-post-install": "cd ../.. && pnpm build",
"eas-build-post-install": "cd ../.. && yarn build",
"update-expo": "npx expo@latest install expo@latest --fix"
},
"dependencies": {
Expand All @@ -30,12 +33,18 @@
"@react-native-async-storage/async-storage": "2.2.0",
"@react-native-community/datetimepicker": "8.4.4",
"@react-native-community/slider": "5.0.1",
"@storybook/addon-ondevice-actions": "^10.2.2-canary.1",
"@storybook/addon-ondevice-backgrounds": "^10.2.2-canary.1",
"@storybook/addon-ondevice-controls": "^10.2.2-canary.1",
"@storybook/addon-ondevice-notes": "^10.2.2-canary.1",
"@storybook/addon-ondevice-actions": "^10.2.2-next.7",
"@storybook/addon-ondevice-backgrounds": "^10.2.2-next.7",
"@storybook/addon-ondevice-controls": "^10.2.2-next.7",
"@storybook/addon-ondevice-notes": "^10.2.2-next.7",
"@storybook/addon-react-native-server": "^1.0.1",
"@storybook/react": "^10.2.2",
"@storybook/react-native": "^10.2.2-canary.1",
"@storybook/react-native-ui-lite": "^10.2.2-canary.1",
"@storybook/react-native": "^10.2.2-next.7",
"@storybook/react-native-ui-lite": "^10.2.2-next.7",
"@storybook/react-native-web-vite": "^10.2.2",
Expand Down
8 changes: 8 additions & 0 deletions packages/react-native/assets/generate/empty.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const view = {
getStorybookUI:
() =>
({ children }) =>
children,
showStorybook: () => {},
createPreparedStoryMapping: async () => {},
};
3 changes: 2 additions & 1 deletion packages/react-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"./preview": "./dist/preview.js",
"./scripts/generate": "./scripts/generate.js",
"./preset": "./preset.js",
"./stub": "./dist/stub.js"
"./stub": "./dist/stub.js",
"./package.json": "./package.json"
},
"files": [
"bin/**/*",
Expand Down
61 changes: 45 additions & 16 deletions packages/react-native/scripts/generate.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
const fs = require('node:fs');
const { networkInterfaces } = require('node:os');
const path = require('node:path');

const {
toRequireContext,
ensureRelativePathHasDot,
getPreviewExists,
resolveAddonFile,
getAddonName,
} = require('./common');
const { normalizeStories, globToRegexp, loadMainConfig } = require('storybook/internal/common');
const {
normalizeStories,
globToRegexp,
loadMainConfig,
optionalEnvToBoolean,
} = require('storybook/internal/common');
const { interopRequireDefault } = require('./require-interop');
const fs = require('fs');
const { networkInterfaces } = require('node:os');

const path = require('path');

const cwd = process.cwd();

Expand Down Expand Up @@ -52,19 +57,47 @@ function getLocalIPAddress() {

async function generate({
configPath,
enabled = true,
useJs = false,
docTools = true,
forceOpen = false,
host = undefined,
port = 7007,
}) {
// here we want to get the ip address and pass it to rn storybook so that devices can connect over lan easily
const channelHost = host === 'auto' ? getLocalIPAddress() : host;
const storybookRequiresLocation = path.resolve(
cwd,
configPath,
`storybook.requires.${useJs ? 'js' : 'ts'}`
);

const storybookEnabled = optionalEnvToBoolean(process.env.STORYBOOK_FORCE_ENABLED) || enabled;
const storybookOpen = optionalEnvToBoolean(process.env.STORYBOOK_FORCE_OPEN) || forceOpen;

if (!storybookEnabled) {
const assetsPath = path.join(
path.dirname(require.resolve('@storybook/react-native/package.json')),
'assets',
'generate'
);
const content = fs.readFileSync(path.join(assetsPath, 'empty.js'), { encoding: 'utf8' });

fs.writeFileSync(storybookRequiresLocation, content, {
encoding: 'utf8',
flag: 'w',
});
return;
}

// here we want to get the ip address and pass it to rn storybook so that devices can connect over lan easily
const envChannelHost = process.env.STORYBOOK_CHANNEL_HOST;
const envChannelPort = process.env.STORYBOOK_CHANNEL_PORT;

const registeredAddons = [];
const enhancers = [];

const channelHost = envChannelHost || (host === 'auto' ? getLocalIPAddress() : host);
const channelPort = envChannelPort || port;

const main = await loadMain({ configPath, cwd });

const storiesSpecifiers = normalizeStories(main.stories, {
Expand Down Expand Up @@ -93,8 +126,6 @@ async function generate({
}`;
});

const registeredAddons = [];

for (const addon of main.addons) {
const registerPath = resolveAddonFile(
getAddonName(addon),
Expand All @@ -108,12 +139,8 @@ async function generate({
}
}

const docToolsAnnotation = 'require("@storybook/react-native/preview")';

const enhancers = [];

if (docTools) {
enhancers.push(docToolsAnnotation);
enhancers.push('require("@storybook/react-native/preview")');
}

for (const addon of main.addons) {
Expand Down Expand Up @@ -154,6 +181,7 @@ declare global {
var view: View;
var STORIES: typeof normalizedStories;
var STORYBOOK_WEBSOCKET: { host: string; port: number } | undefined;
var STORYBOOK_FORCE_OPEN: boolean | undefined;
}
`;

Expand All @@ -170,9 +198,10 @@ ${useJs ? '' : globalTypes}

const annotations = ${annotations};

globalThis.STORIES = normalizedStories;
${channelHost ? `globalThis.STORYBOOK_WEBSOCKET = { host: '${channelHost}', port: ${port ?? 7007} };` : ''}

globalThis.STORIES = normalizedStories;
${channelHost ? `globalThis.STORYBOOK_WEBSOCKET = { host: '${channelHost}', port: ${channelPort} };` : ''}
${storybookOpen ? `globalThis.STORYBOOK_FORCE_OPEN = true;` : ''}
${useJs ? '' : '// @ts-ignore'}
module?.hot?.accept?.();

Expand Down
21 changes: 20 additions & 1 deletion packages/react-native/src/View.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ export class View {
return channel;
};

showStorybook = (v: boolean = true) => {
this._channel.emit('SHOW_STORYBOOK', v);
};

createPreparedStoryMapping = async () => {
await this._preview.ready().then(() =>
Promise.all(
Expand Down Expand Up @@ -269,7 +273,11 @@ export class View {
const self = this;

// eslint-disable-next-line react/display-name
return () => {
return ({ children }: { children: React.ReactNode }) => {
const isShownInitially =
!children || !!self._channel.last('SHOW_STORYBOOK') || !!globalThis.STORYBOOK_FORCE_OPEN;
const [isShown, setIsShown] = useState(isShownInitially);

const setContext = useSetStoryContext();
const story = useStoryContext();
const colorScheme = useColorScheme();
Expand All @@ -281,6 +289,13 @@ export class View {
[colorScheme]
);

// activate the storybook
useEffect(() => {
self._channel.on('SHOW_STORYBOOK', (v = true) => {
setIsShown(v);
});
}, []);

// deep link handling
useEffect(() => {
const listener = Linking.addEventListener('url', ({ url }) => {
Expand Down Expand Up @@ -402,6 +417,10 @@ export class View {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ready, update]);

if (!isShown) {
return children || null;
}

if (!ready) {
return (
<RNView
Expand Down
Loading