From b98cfa8a2be0a192317654067178d2c918f69106 Mon Sep 17 00:00:00 2001 From: Daniel Williams Date: Mon, 15 Dec 2025 00:02:04 +0000 Subject: [PATCH 01/20] feat: csf factories --- examples/expo-example/.rnstorybook/main.ts | 8 +++---- .../expo-example/.rnstorybook/preview.tsx | 11 +++++---- .../ControlExample/ControlExample.stories.tsx | 10 ++++---- packages/react-native/package.json | 3 ++- packages/react-native/src/index.ts | 24 +++++++------------ packages/react-native/src/node/index.ts | 5 ++++ packages/react-native/src/polyfill.ts | 2 +- packages/react-native/src/types/config.ts | 10 ++++++++ packages/react-native/tsup.config.ts | 15 ++++++++++-- 9 files changed, 53 insertions(+), 35 deletions(-) create mode 100644 packages/react-native/src/node/index.ts create mode 100644 packages/react-native/src/types/config.ts diff --git a/examples/expo-example/.rnstorybook/main.ts b/examples/expo-example/.rnstorybook/main.ts index 0ee12e40c1..00213cec45 100644 --- a/examples/expo-example/.rnstorybook/main.ts +++ b/examples/expo-example/.rnstorybook/main.ts @@ -1,6 +1,6 @@ -import type { StorybookConfig } from '@storybook/react-native'; +import { defineMain } from '@storybook/react-native/node'; -const main: StorybookConfig = { +export default defineMain({ stories: [ '../components/**/*.stories.?(ts|tsx|js|jsx)', '../other_components/**/*.stories.?(ts|tsx|js|jsx)', @@ -23,6 +23,4 @@ const main: StorybookConfig = { }, framework: '@storybook/react-native', -}; - -export default main; +}); diff --git a/examples/expo-example/.rnstorybook/preview.tsx b/examples/expo-example/.rnstorybook/preview.tsx index 2b47d26205..565a8f5d97 100644 --- a/examples/expo-example/.rnstorybook/preview.tsx +++ b/examples/expo-example/.rnstorybook/preview.tsx @@ -1,9 +1,11 @@ import { Appearance } from 'react-native'; import { withBackgrounds } from '@storybook/addon-ondevice-backgrounds'; -import type { Preview } from '@storybook/react-native'; +import { definePreview } from '@storybook/react-native'; -const preview: Preview = { +export default definePreview({ + addons: [], decorators: [withBackgrounds], + parameters: { actions: { argTypesRegex: '^on[A-Z].*' }, controls: { @@ -26,6 +28,7 @@ const preview: Preview = { storybookUIVisibility: 'visible', // visible, hidden backgrounds: { default: Appearance.getColorScheme() === 'dark' ? 'dark' : 'plain', + // @ts-expect-error - backgrounds not compatible yet values: [ { name: 'plain', value: 'white' }, { name: 'dark', value: '#333' }, @@ -33,6 +36,4 @@ const preview: Preview = { ], }, }, -}; - -export default preview; +}); diff --git a/examples/expo-example/components/ControlExamples/ControlExample/ControlExample.stories.tsx b/examples/expo-example/components/ControlExamples/ControlExample/ControlExample.stories.tsx index 65070ba30b..f42259743c 100644 --- a/examples/expo-example/components/ControlExamples/ControlExample/ControlExample.stories.tsx +++ b/examples/expo-example/components/ControlExamples/ControlExample/ControlExample.stories.tsx @@ -1,7 +1,7 @@ -import { Meta, StoryObj } from '@storybook/react-native'; import { ControlExample } from './ControlExample'; +import preview from '../../../.rnstorybook/preview'; -const meta = { +const meta = preview.meta({ component: ControlExample, args: { name: 'Storyteller', @@ -74,10 +74,8 @@ const meta = { control: { type: 'nonexistent_type' }, }, }, -} satisfies Meta; +}); export default meta; -type ControlExampleStory = StoryObj; - -export const Example: ControlExampleStory = {}; +export const Example = meta.story({}); diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 360fb53ca0..7d2ce252d0 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -27,7 +27,8 @@ "./preview": "./dist/preview.js", "./scripts/generate": "./scripts/generate.js", "./preset": "./preset.js", - "./stub": "./dist/stub.js" + "./stub": "./dist/stub.js", + "./node": "./dist/node/index.js" }, "files": [ "bin/**/*", diff --git a/packages/react-native/src/index.ts b/packages/react-native/src/index.ts index 060405276e..c2355e17c2 100644 --- a/packages/react-native/src/index.ts +++ b/packages/react-native/src/index.ts @@ -1,26 +1,20 @@ -import type { StorybookConfig as StorybookConfigBase } from 'storybook/internal/types'; -import type { ReactNativeOptions } from './Start'; export { darkTheme, theme, type Theme } from '@storybook/react-native-theming'; -export { start, prepareStories, getProjectAnnotations, updateView } from './Start'; -export type { View, Storage, InitialSelection, ThemePartial, Params } from './View'; +export { getProjectAnnotations, prepareStories, start, updateView } from './Start'; +export type { InitialSelection, Params, Storage, ThemePartial, View } from './View'; -export interface StorybookConfig { - stories: StorybookConfigBase['stories']; - addons: Array }>; - // TODO move this to params - reactNative?: ReactNativeOptions; - framework?: '@storybook/react-native'; -} +export type { StorybookConfig } from './types/config'; export type { - Meta, - StoryFn, - StoryObj, Args, ArgTypes, - Preview, Decorator, Loader, + Meta, Parameters, + Preview, + StoryFn, + StoryObj, } from '@storybook/react'; + +export { __definePreview as definePreview } from '@storybook/react'; diff --git a/packages/react-native/src/node/index.ts b/packages/react-native/src/node/index.ts new file mode 100644 index 0000000000..5b3a88448e --- /dev/null +++ b/packages/react-native/src/node/index.ts @@ -0,0 +1,5 @@ +import type { StorybookConfig } from '../types/config'; + +export function defineMain(config: StorybookConfig) { + return config; +} diff --git a/packages/react-native/src/polyfill.ts b/packages/react-native/src/polyfill.ts index 3ff2b34c8f..c8009b09db 100644 --- a/packages/react-native/src/polyfill.ts +++ b/packages/react-native/src/polyfill.ts @@ -1,4 +1,4 @@ -import { Platform } from 'react-native-web'; +import { Platform } from 'react-native'; if (Platform.OS !== 'web') { // We polyfill URLSearchParams for React Native since URLSearchParams.get is not implemented yet is used in storybook diff --git a/packages/react-native/src/types/config.ts b/packages/react-native/src/types/config.ts new file mode 100644 index 0000000000..39e5a12ce6 --- /dev/null +++ b/packages/react-native/src/types/config.ts @@ -0,0 +1,10 @@ +import type { Preset, StorybookConfig as StorybookConfigBase } from 'storybook/internal/types'; +import type { ReactNativeOptions } from '../Start'; + +export interface StorybookConfig { + stories: StorybookConfigBase['stories']; + addons: Preset[]; + // TODO remove this + reactNative?: ReactNativeOptions; + framework?: '@storybook/react-native'; +} diff --git a/packages/react-native/tsup.config.ts b/packages/react-native/tsup.config.ts index 7905abae9f..1dff66c6b0 100644 --- a/packages/react-native/tsup.config.ts +++ b/packages/react-native/tsup.config.ts @@ -2,12 +2,23 @@ import { defineConfig } from 'tsup'; export default defineConfig((options) => { return { - entry: ['src/index.ts', 'src/preview.ts', 'src/metro/withStorybook.ts', 'src/stub.tsx'], + entry: [ + 'src/index.ts', + 'src/preview.ts', + 'src/metro/withStorybook.ts', + 'src/stub.tsx', + 'src/node/index.ts', + ], // minify: !options.watch, clean: !options.watch, dts: !options.watch ? { - entry: ['src/index.ts', 'src/preview.ts', 'src/metro/withStorybook.ts'], + entry: [ + 'src/index.ts', + 'src/preview.ts', + 'src/metro/withStorybook.ts', + 'src/node/index.ts', + ], resolve: true, } : false, From 9387241b31177d5aa5b1fb96fc576281e1f9b9ac Mon Sep 17 00:00:00 2001 From: Daniel Williams Date: Fri, 27 Feb 2026 14:50:23 +0000 Subject: [PATCH 02/20] remove comment --- packages/react-native/src/types/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react-native/src/types/config.ts b/packages/react-native/src/types/config.ts index b4617831af..f4633f7913 100644 --- a/packages/react-native/src/types/config.ts +++ b/packages/react-native/src/types/config.ts @@ -9,7 +9,6 @@ export interface Features { export interface StorybookConfig { stories: StorybookConfigBase['stories']; addons: Preset[]; - // TODO move this to params reactNative?: ReactNativeOptions; features?: Features; framework?: '@storybook/react-native'; From a2177ced714268467d127c681410ca5eced7fef3 Mon Sep 17 00:00:00 2001 From: Daniel Williams Date: Fri, 27 Feb 2026 15:15:15 +0000 Subject: [PATCH 03/20] feat: add factories examples and tests --- .../Actions.factories.stories.tsx | 33 ++++++ .../ActionExample/Actions.factories.test.tsx | 18 +++ .../BackgroundCsf.factories.stories.tsx | 32 +++++ .../BackgroundCsf.factories.test.tsx | 9 ++ .../Boolean/Boolean.factories.stories.tsx | 16 +++ .../Boolean/Boolean.factories.test.tsx | 14 +++ .../Color/Color.factories.stories.tsx | 20 ++++ .../Color/Color.factories.test.tsx | 8 ++ .../Date/Date.factories.stories.tsx | 14 +++ .../Date/Date.factories.test.tsx | 10 ++ .../Number/Number.factories.stories.tsx | 30 +++++ .../Number/Number.factories.test.tsx | 14 +++ .../Object/Object.factories.stories.tsx | 17 +++ .../Object/Object.factories.test.tsx | 10 ++ .../Radio/Radio.factories.stories.tsx | 23 ++++ .../Radio/Radio.factories.test.tsx | 8 ++ .../SelectWithNumber.factories.stories.tsx | 14 +++ .../Select/Select.factories.stories.tsx | 75 ++++++++++++ .../Select/Select.factories.test.tsx | 21 ++++ .../Text/Text.factories.stories.tsx | 11 ++ .../Text/Text.factories.test.tsx | 8 ++ .../WebCompatibility.factories.stories.tsx | 75 ++++++++++++ .../DeepControls.factories.stories.tsx | 67 +++++++++++ .../HiddenControls.factories.stories.tsx | 34 ++++++ .../TextInput.factories.stories.tsx | 17 +++ .../InputExample/TextInput.factories.test.tsx | 8 ++ .../InteractionExample.factories.stories.tsx | 109 ++++++++++++++++++ .../LoginForm/LoginForm.factories.stories.tsx | 53 +++++++++ .../TextInput/TextInput.factories.stories.tsx | 76 ++++++++++++ .../NotesExample.factories.stories.tsx | 96 +++++++++++++++ .../StoryName/StoryName.factories.stories.tsx | 35 ++++++ 31 files changed, 975 insertions(+) create mode 100644 examples/expo-example/components/ActionExample/Actions.factories.stories.tsx create mode 100644 examples/expo-example/components/ActionExample/Actions.factories.test.tsx create mode 100644 examples/expo-example/components/BackgroundExample/BackgroundCsf.factories.stories.tsx create mode 100644 examples/expo-example/components/BackgroundExample/BackgroundCsf.factories.test.tsx create mode 100644 examples/expo-example/components/ControlExamples/Boolean/Boolean.factories.stories.tsx create mode 100644 examples/expo-example/components/ControlExamples/Boolean/Boolean.factories.test.tsx create mode 100644 examples/expo-example/components/ControlExamples/Color/Color.factories.stories.tsx create mode 100644 examples/expo-example/components/ControlExamples/Color/Color.factories.test.tsx create mode 100644 examples/expo-example/components/ControlExamples/Date/Date.factories.stories.tsx create mode 100644 examples/expo-example/components/ControlExamples/Date/Date.factories.test.tsx create mode 100644 examples/expo-example/components/ControlExamples/Number/Number.factories.stories.tsx create mode 100644 examples/expo-example/components/ControlExamples/Number/Number.factories.test.tsx create mode 100644 examples/expo-example/components/ControlExamples/Object/Object.factories.stories.tsx create mode 100644 examples/expo-example/components/ControlExamples/Object/Object.factories.test.tsx create mode 100644 examples/expo-example/components/ControlExamples/Radio/Radio.factories.stories.tsx create mode 100644 examples/expo-example/components/ControlExamples/Radio/Radio.factories.test.tsx create mode 100644 examples/expo-example/components/ControlExamples/Reproductions/SelectWithNumber.factories.stories.tsx create mode 100644 examples/expo-example/components/ControlExamples/Select/Select.factories.stories.tsx create mode 100644 examples/expo-example/components/ControlExamples/Select/Select.factories.test.tsx create mode 100644 examples/expo-example/components/ControlExamples/Text/Text.factories.stories.tsx create mode 100644 examples/expo-example/components/ControlExamples/Text/Text.factories.test.tsx create mode 100644 examples/expo-example/components/ControlExamples/WebCompatibility/WebCompatibility.factories.stories.tsx create mode 100644 examples/expo-example/components/DeepControls/DeepControls.factories.stories.tsx create mode 100644 examples/expo-example/components/HiddenControls/HiddenControls.factories.stories.tsx create mode 100644 examples/expo-example/components/InputExample/TextInput.factories.stories.tsx create mode 100644 examples/expo-example/components/InputExample/TextInput.factories.test.tsx create mode 100644 examples/expo-example/components/InteractionExample/InteractionExample.factories.stories.tsx create mode 100644 examples/expo-example/components/LoginDocsExample/LoginForm/LoginForm.factories.stories.tsx create mode 100644 examples/expo-example/components/LoginDocsExample/TextInput/TextInput.factories.stories.tsx create mode 100644 examples/expo-example/components/NotesExample/NotesExample.factories.stories.tsx create mode 100644 examples/expo-example/components/StoryName/StoryName.factories.stories.tsx diff --git a/examples/expo-example/components/ActionExample/Actions.factories.stories.tsx b/examples/expo-example/components/ActionExample/Actions.factories.stories.tsx new file mode 100644 index 0000000000..c6a0e8b769 --- /dev/null +++ b/examples/expo-example/components/ActionExample/Actions.factories.stories.tsx @@ -0,0 +1,33 @@ +import { ActionButton } from './Actions'; +import { action } from 'storybook/actions'; +// import { fn } from 'storybook/test'; +import preview from '../../.rnstorybook/preview'; + +const meta = preview.meta({ + component: ActionButton, + parameters: { + notes: ` +# Button + +This is a button component. +You use it like this: + +\`\`\`tsx +