Skip to content

Commit

Permalink
Merge pull request #18824 from storybookjs/tom/sb-581-copy-in-the-ren…
Browse files Browse the repository at this point in the history
…dererframework-specific

Copy example stories over from renderer + addons
  • Loading branch information
tmeasday authored Aug 2, 2022
2 parents 4670411 + e57b1d5 commit c179d1a
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 6 deletions.
19 changes: 19 additions & 0 deletions code/addons/actions/template/stories/basics.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// TODO -- for now react, going to generalise
import React, { FC } from 'react';

import { action } from '@storybook/addon-actions';

// TODO -- this needs to be a generic component
const Button: FC<{ onClick: () => void }> = ({ onClick, children }) => (
<button type="button" onClick={onClick}>
{children}
</button>
);

export default {
component: Button,
};

export const BasicExample = {
args: { onClick: action('hello-world') },
};
1 change: 1 addition & 0 deletions code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.5",
"esbuild": "^0.14.48",
"esbuild-loader": "^2.19.0",
"esbuild-plugin-alias": "^0.2.1",
"eslint": "^7.17.0",
"eslint-plugin-cypress": "^2.11.2",
Expand Down
27 changes: 27 additions & 0 deletions code/renderers/react/template/stories/decorators.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { FC } from 'react';
import type { ComponentStory, ComponentMeta } from '@storybook/react';

const Component: FC = () => <p>Story</p>;

export default {
component: Component,
decorators: [
(Story) => (
<>
<p>Component Decorator</p>
<Story />
</>
),
],
} as ComponentMeta<typeof Component>;

export const All: ComponentStory<typeof Component> = {
decorators: [
(Story) => (
<>
<p>Local Decorator</p>
<Story />
</>
),
],
};
17 changes: 17 additions & 0 deletions code/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9009,6 +9009,7 @@ __metadata:
enzyme: ^3.11.0
enzyme-adapter-react-16: ^1.15.5
esbuild: ^0.14.48
esbuild-loader: ^2.19.0
esbuild-plugin-alias: ^0.2.1
eslint: ^7.17.0
eslint-plugin-cypress: ^2.11.2
Expand Down Expand Up @@ -20474,6 +20475,22 @@ __metadata:
languageName: node
linkType: hard

"esbuild-loader@npm:^2.19.0":
version: 2.19.0
resolution: "esbuild-loader@npm:2.19.0"
dependencies:
esbuild: ^0.14.39
joycon: ^3.0.1
json5: ^2.2.0
loader-utils: ^2.0.0
tapable: ^2.2.0
webpack-sources: ^2.2.0
peerDependencies:
webpack: ^4.40.0 || ^5.0.0
checksum: 309b4bd169ffd1d743ad7099182323a179dec789cd5eb4f5f0258c1c13034a154917679e2402bfcedd90c9b03d06d773e97fe4aa1056274dc43d30633c5707e1
languageName: node
linkType: hard

"esbuild-netbsd-64@npm:0.14.49":
version: 0.14.49
resolution: "esbuild-netbsd-64@npm:0.14.49"
Expand Down
1 change: 0 additions & 1 deletion sandbox/react
Submodule react deleted from 28e606
89 changes: 84 additions & 5 deletions scripts/example.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
/* eslint-disable no-restricted-syntax, no-await-in-loop */
import path from 'path';
import { remove, pathExists, readJSON, writeJSON } from 'fs-extra';
import prompts from 'prompts';

import { getOptionsOrPrompt } from './utils/options';
import { executeCLIStep } from './utils/cli-step';
import { exec } from '../code/lib/cli/src/repro-generators/scripts';
import { getInterpretedFile } from '../code/lib/core-common';
import { readConfig, writeConfig } from '../code/lib/csf-tools';
import { babelParse } from '../code/lib/csf-tools/src/babelParse';

const frameworks = ['react', 'angular'];
const addons = ['a11y', 'storysource'];
const defaultAddons = [
'actions',
'backgrounds',
'controls',
'docs',
'highlight',
'links',
'interactions',
'measure',
'outline',
'toolbars',
'viewport',
];
const examplesDir = path.resolve(__dirname, '../examples');
const codeDir = path.resolve(__dirname, '../code');

// TODO -- how to encode this information
const renderersMap = { react: 'react', angular: 'angular' };

async function getOptions() {
return getOptionsOrPrompt('yarn example', {
framework: {
Expand Down Expand Up @@ -116,11 +136,63 @@ const addPackageScripts = async ({
await writeJSON(packageJsonPath, packageJson, { spaces: 2 });
};

async function readMainConfig({ cwd }: { cwd: string }) {
const configDir = path.join(cwd, '.storybook');
const mainConfigPath = getInterpretedFile(path.resolve(configDir, 'main'));
return readConfig(mainConfigPath);
}

// NOTE: the test regexp here will apply whether the path is symlink-preserved or otherwise
const loaderPath = require.resolve('../code/node_modules/esbuild-loader');
const webpackFinalCode = `
(config) => ({
...config,
module: {
...config.modules,
rules: [
{
test: [/\\/node_modules\\/@storybook\\/[^/]*\\/template\\/stories\\//],
loader: '${loaderPath}',
options: {
loader: 'tsx',
target: 'es2015',
},
},
...config.module.rules,
],
},
})`;

// paths are of the form 'node_modules/@storybook/react'
async function addStories(paths: string[], { cwd }: { cwd: string }) {
const mainConfig = await readMainConfig({ cwd });

const stories = mainConfig.getFieldValue(['stories']) as string[];
const extraStoryDirsAndExistence = await Promise.all(
paths
.map((p) => path.join(p, 'template', 'stories'))
.map(async (p) => [p, await pathExists(path.resolve(codeDir, p))] as const)
);

const extraStories = extraStoryDirsAndExistence
.filter(([, exists]) => exists)
.map(([p]) => path.join('..', p, '*.stories.@(js|jsx|ts|tsx)'));
mainConfig.setFieldValue(['stories'], [...stories, ...extraStories]);

mainConfig.setFieldNode(
['webpackFinal'],
// @ts-ignore (not sure why TS complains here, it does exist)
babelParse(webpackFinalCode).program.body[0].expression
);

await writeConfig(mainConfig);
}

async function main() {
const optionValues = await getOptions();

const { framework, forceDelete, forceReuse, link, dryRun } = optionValues;
const cwd = path.join(examplesDir, framework as string);
const cwd = path.join(examplesDir, framework);

const exists = await pathExists(cwd);
let shouldDelete = exists && !forceReuse;
Expand All @@ -146,19 +218,26 @@ async function main() {
dryRun,
});

// TODO -- can we get the options type to return something more specific
const renderer = renderersMap[framework as 'react' | 'angular'];

const storiesToAdd = [] as string[];
storiesToAdd.push(path.join('node_modules', '@storybook', renderer));

// TODO -- sb add <addon> doesn't actually work properly:
// - installs in `deps` not `devDeps`
// - does a `workspace:^` install (what does that mean?)
// - doesn't add to `main.js`

// eslint-disable-next-line no-restricted-syntax
for (const addon of optionValues.addon as string[]) {
for (const addon of optionValues.addon) {
const addonName = `@storybook/addon-${addon}`;
// eslint-disable-next-line no-await-in-loop
await executeCLIStep(steps.add, { argument: addonName, cwd, dryRun });
}

// TODO copy stories
for (const addon of [...defaultAddons, ...optionValues.addon]) {
storiesToAdd.push(path.join('node_modules', '@storybook', `addon-${addon}`));
}
await addStories(storiesToAdd, { cwd });

if (link) {
await executeCLIStep(steps.link, {
Expand Down

0 comments on commit c179d1a

Please sign in to comment.