diff --git a/README.md b/README.md index 706ecd8..8601189 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,12 @@ The route Storybook Server uses to render components. You shouldn't need to chan Default: `config('app.url') . '/storybook_preview'` +#### `storybook_addons` + +An array of custom [storybook addons](https://storybook.js.org/integrations/) you'd like to use in your project. Note that not all addons are compatible with Storybook Server. Read about how to configure addons in your stories in the Storybook Configuration section below. + +Default: `[]` + #### `auto_documentation` Blast can automatically generate documentation pages in the form of stories based on your Tailwind config. Use this array to specify which documentation pages to generate. All options are loaded by default. @@ -337,7 +343,12 @@ There are certain Storybook elements you can configure from within your story bl ], 'actions' => [ 'handles' => ['mouseover', 'click'] - ] + ], + 'addons' => [ + 'jira' => [ + 'id' => 'ABC-123' + ] + ], ]) ``` @@ -352,6 +363,7 @@ The supported options for this directive are: - `args` - an array of static data used to create storybook fields. You can read more about that [here](https://github.com/storybookjs/storybook/tree/main/app/server#server-rendering). The keys in the array are passed to the blade view and updated when the fields are updated in storybook. - `argTypes` - an array to define the args used for the controls. You can read more about them [here](https://storybook.js.org/docs/react/api/argtypes) - `actions.handles` - an array defining the events that are passed to the `@storybook-actions` addon. You can read more about actions [here](https://storybook.js.org/docs/react/essentials/actions) - See the Action Event Handlers heading. +- `addons` - an array to define options for any custom addons. Any options defined here are added to the parameters array in the story. Some addons require you to modify storybook config files which can be done by publishing them to your project directory. ## Customizing the story view diff --git a/config/blast.php b/config/blast.php index 0775592..bc85705 100644 --- a/config/blast.php +++ b/config/blast.php @@ -8,6 +8,8 @@ 'storybook_server_url' => env('STORYBOOK_SERVER_HOST', env('APP_URL')) . '/storybook_preview', + 'storybook_addons' => [], + /** * Specify which documentation pages to generate for the Tailwind classes used in your application * Defaults to `[]` which will render all diff --git a/src/Commands/GenerateStories.php b/src/Commands/GenerateStories.php index fd541c8..6ca86be 100644 --- a/src/Commands/GenerateStories.php +++ b/src/Commands/GenerateStories.php @@ -441,6 +441,12 @@ private function buildChildTemplate($item) ]; } } + + if (Arr::has($options, 'addons')) { + foreach ($options['addons'] as $key => $addon) { + $data['parameters'][$key] = $addon; + } + } } $data['hash'] = $this->getBladeChecksum( diff --git a/src/Traits/Helpers.php b/src/Traits/Helpers.php index 3ca76b5..aaaa190 100644 --- a/src/Traits/Helpers.php +++ b/src/Traits/Helpers.php @@ -103,6 +103,7 @@ private function installDependencies($npmInstall) $updateStorybook = $this->checkStorybookVersions( $this->storybookInstallVersion, ); + $updateAddons = true; if ($npmInstall || (!$npmInstall && !$depsInstalled)) { $this->runProcessInBlast( @@ -113,7 +114,13 @@ private function installDependencies($npmInstall) ); $this->installStorybook($this->storybookInstallVersion); + + $this->installAddons(); } else { + if ($updateAddons) { + $this->installAddons(); + } + if ($updateStorybook) { $this->installStorybook($this->storybookInstallVersion); } @@ -186,11 +193,11 @@ private function installStorybook($storybookVersion) } } - private function getInstalledStorybookVersion() + private function getInstalledPackageVersion($package) { $version = false; $rawOutput = $this->runProcessInBlast( - ['npm', 'list', 'storybook', '--json'], + ['npm', 'list', $package, '--json'], false, null, false, @@ -198,8 +205,8 @@ private function getInstalledStorybookVersion() ); $data = json_decode($rawOutput, true); - if (isset($data['dependencies']['storybook'])) { - $version = $data['dependencies']['storybook']['version']; + if (isset($data['dependencies'][$package])) { + $version = $data['dependencies'][$package]['version']; } return $version; @@ -208,7 +215,9 @@ private function getInstalledStorybookVersion() private function checkStorybookVersions($storybookVersion) { // check if version matches installed version - $installedStorybookVersion = $this->getInstalledStorybookVersion(); + $installedStorybookVersion = $this->getInstalledPackageVersion( + 'storybook', + ); if ($installedStorybookVersion !== $this->storybookInstallVersion) { $this->newLine(); @@ -221,4 +230,75 @@ private function checkStorybookVersions($storybookVersion) return false; } + + private function storybookConfigPublished() + { + $projectMainConfigPath = base_path('.storybook/main.js'); + + return $this->filesystem->exists($projectMainConfigPath); + } + + private function storybookConfigPath($path = false) + { + $configPublished = $this->storybookConfigPublished(); + $configPath = $configPublished + ? base_path('.storybook') + : $this->vendorPath . '/.storybook'; + + if ($path) { + $path = Str::start($path, '/'); + } + return Str::of($configPath)->finish($path); + } + + private function installAddons() + { + $storybookConfigPublished = $this->storybookConfigPublished(); + $mainJsPath = $this->storybookConfigPath('main.js'); + $mainJsContents = $this->filesystem->get($mainJsPath); + $addons = config('blast.storybook_addons'); + $installedAddons = []; + + if (!$addons) { + return 0; + } + + $this->newLine(); + foreach ($addons as $addon) { + $this->info('Found custom addon - ' . $addon); + + $addonInstalled = $this->getInstalledPackageVersion($addon); + + if (!$addonInstalled) { + $this->info('Installing ' . $addon); + + $this->runProcessInBlast(['npm', 'install', $addon]); + } else { + $this->info('Addon already installed. Skipping installation.'); + } + + if (!Str::contains($mainJsContents, $addon)) { + $this->info('Addon missing from .storybook/main.js. Adding.'); + + $addonName = Str::of($addon); + if ($storybookConfigPublished) { + $addonName = $addonName->start( + '../vendor/area17/blast/node_modules/', + ); + } + + $installedAddons[] = $addonName->start("'")->finish("'"); + } + } + + if (filled($installedAddons)) { + $this->filesystem->replaceInFile( + 'addons: [', + "addons: [\n" . implode(",\n", $installedAddons) . ',', + $mainJsPath, + ); + } + + $this->info('Addons installed'); + } }