npm package: @marklb/storybook-angular-initial-url
Description: Set an initial url for a Storybook story for Angular.
Author: Mark Berry
Latest version: 2.0.0

# Storybook Angular Initial URL

Configures a story with an initial url, for stories using `@angular/router`.

## Getting Started

### Install

```sh
npm i @marklb/storybook-angular-initial-url
```

### Configure Routes

This package does not provide routes, so make sure your story includes the router providers.

Example:

```ts
import { applicationConfig, Meta, StoryObj } from '@storybook/angular'
import { provideRouter } from '@angular/router'
import { provideLocationMocks } from '@angular/common/testing'

const meta: Meta<MyPageComponent> = {
  component: MyPageComponent,
  decorators: [
    applicationConfig({
      providers: [
        provideLocationMocks(),
        provideRouter(...),
      ],
    }),
  ],
}

export default meta
type Story = StoryObj<MyPageComponent>

export const Basic: Story = {}
```

### Set Initial URL

Two ways to configure the initial route are provided.

- `provideStoryInitialUrl` A simple Angular provider.
- `initialUrlFromArgs` Storybook decorator that sets the url in the story args.

#### Angular Provider

```ts
import { applicationConfig, Meta, StoryObj } from '@storybook/angular'
import { provideRouter } from '@angular/router'
import { provideLocationMocks } from '@angular/common/testing'
import { provideStoryInitialUrl } from '@marklb/storybook-angular-initial-url'

const meta: Meta<MyPageComponent> = {
  component: MyPageComponent,
  decorators: [
    applicationConfig({
      providers: [
        provideLocationMocks(),
        provideRouter([
          { path: '', component: DashboardComponent },
          { path: 'content-1', component: ContentOneComponent },
          { path: 'content-2', component: ContentTwoComponent },
          { path: 'content-3', component: ContentThreeComponent },
        ]),
        provideStoryInitialUrl('/content-2')
      ],
    }),
  ],
}

export default meta
type Story = StoryObj<MyPageComponent>

export const Basic: Story = {}
```

#### Storybook Decorator

```ts
import { applicationConfig, Meta, StoryObj } from '@storybook/angular'
import { provideRouter } from '@angular/router'
import { provideLocationMocks } from '@angular/common/testing'
import { initialUrlFromArgs } from '@marklb/storybook-angular-initial-url'

/** args that are not a property on your component. */
type ExtraArgs = {
  initialUrl?: string
}

type StoryComponentType = MyPageComponent & ExtraArgs

const meta: Meta<StoryComponentType> = {
  component: MyPageComponent,
  decorators: [
    applicationConfig({
      providers: [
        provideLocationMocks(),
        provideRouter([
          { path: '', component: DashboardComponent },
          { path: 'content-1', component: ContentOneComponent },
          { path: 'content-2', component: ContentTwoComponent },
          { path: 'content-3', component: ContentThreeComponent },
        ]),
      ],
    }),
    initialUrlFromArgs(),
  ],
  argTypes: {
    initialUrl: {
      control: {
        type: 'select',
      },
      options: [ '/content-1', '/content-2', '/content-3' ],
    },
  },
  args: {
    initialUrl: '/content-2',
  },
}

export default meta
type Story = StoryObj<StoryComponentType>

export const Basic: Story = {}
```

If your story already has an arg named `initialUrl`, `argName` option can set a different arg to read the url from.

```ts
initialUrlFromArgs({ argName: '/content-3' })
```

The rules for when the story needs to rerender should be similar to how Storybook handles inputs. So, if the `initialUrl` arg changes then the route should change, without rerendering the story. If you want to force the story to rerender, when the arg changes, then set the `rerender` option.

```ts
initialUrlFromArgs({ rerender: true })
```