Skip to content

Angular: Add a component snippet format - #35799

Closed
valentinpalkovic wants to merge 8 commits into
valentin/angular-story-docs-3-warningfrom
valentin/angular-story-docs-4-component-format
Closed

valentinpalkovic wants to merge 8 commits into
valentin/angular-story-docs-3-warningfrom
valentin/angular-story-docs-4-component-format

Conversation

@valentinpalkovic

@valentinpalkovic valentinpalkovic commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

What I did

The snippet the earlier slices produce is a bare template fragment:

<sb-button [label]="'Save'" [count]="3" (clicked)="clicked($event)"></sb-button>

That reads fine next to a rendered story, but you cannot do anything with it. An Angular template only exists inside a component, so there is nowhere to paste this, and an agent handed it has to guess the rest.

framework.options.snippetFormat picks the shape:

framework: {
  name: '@storybook/angular-vite',
  options: { snippetFormat: 'component' }, // 'template' is the default
}

'component' wraps the same markup in the host it needs to compile, and the payload grows the matching import block. Both payloads below are real output for the same fixture, captured from a run through the analyzer:

// snippetFormat: 'template'
{
  "id": "example-button",
  "name": "ButtonComponent",
  "path": "capture-tmp/button.stories.ts",
  "stories": {
    "example-button--basic": {
      "id": "example-button--basic",
      "name": "Basic",
      "snippet": "<sb-button [label]=\"'Save'\" [count]=\"3\" (clicked)=\"clicked($event)\"></sb-button>"
    }
  }
}
// snippetFormat: 'component'
{
  "id": "example-button",
  "name": "ButtonComponent",
  "path": "capture-tmp/button.stories.ts",
  "import": "import { Component } from '@angular/core';\nimport { ButtonComponent } from './button.component';",
  "stories": {
    "example-button--basic": {
      "id": "example-button--basic",
      "name": "Basic",
      "snippet": "@Component({\n  selector: 'app-root',\n  template: `<sb-button [label]=\"'Save'\" [count]=\"3\" (clicked)=\"clicked($event)\"></sb-button>`,\n  imports: [ButtonComponent],\n})\nexport class App {\n  clicked(event: unknown) {}\n}"
    }
  }
}

Which renders as:

import { Component } from '@angular/core';
import { ButtonComponent } from './button.component';

@Component({
  selector: 'app-root',
  template: `<sb-button [label]="'Save'" [count]="3" (clicked)="clicked($event)"></sb-button>`,
  imports: [ButtonComponent],
})
export class App {
  clicked(event: unknown) {}
}

Where the wrapper sits relative to what the earlier slices already do:

story file ──▶ CSF parse ──▶ markup ─────────────────────────────▶ story.snippet
                                │   (template: unchanged)
                                │
                                └──▶ scan markup for the output ──▶ angularHostComponent
                                     bindings it actually carries        │
                                                                         ▼
                                                            story.snippet ('component')
component meta ──▶ class name + export name + specifier ──▶ angularHostImports
                                                                         │
                                                                         ▼
                                                                  payload.import

Three decisions worth a look

Handlers are read back off the markup, not assumed. Angular's template type checking resolves (clicked)="clicked($event)" against the host class, so a wrapper missing that method emits an example that does not compile, which would defeat the point of the format. Declaring a method for every output is wrong in the other direction: argsToTemplate is the idiom the Angular docs use everywhere, and it honours include / exclude, so a story that filtered an output out would get a member its template never references. The wrapper asks the markup instead:

const boundOutputs = (markup: string, outputs: readonly string[]): string[] =>
  outputs.filter((name) => markup.includes(bindingAttributes({ inputs: [], outputs: [name] })[0]));

Reusing bindingAttributes rather than a fresh regex means the check cannot drift from the grammar that produced the markup in the first place.

A payload with no snippets gets no import block. The provider deliberately still emits description-only stories when the analyzer cannot resolve a component. Advertising an import block for markup that was never produced would make those payloads look like they carry code. Both the wrapper and payload.import are gated on a snippet actually existing.

'template' stays the default. Flipping it is a one-line change to DEFAULT_SNIPPET_FORMAT, but leaving it means this PR changes nothing for existing users, and the 15 recorded server-snippet-*.snapshot browser-parity baselines stay valid untouched.

Command What it does Run from
yarn test --project "@storybook/angular-vite" Both formats, plus wrapper edge cases: default and aliased exports, selector-less components, non-identifier output names, template-literal escaping repo root
node scripts/check/check-package.ts --cwd code/frameworks/angular-vite Type-checks the package on its own repo root

A wrapper that guessed its handlers instead of reading them fails like this:

 × src/docgen/story-docs-build.test.ts > buildStoryDocsPayload in component format > declares handlers only for the outputs the story kept
   → expected '<sb-button [label]="\'Save\'" (clicke…' to contain 'clicked(event: unknown) {}'
 × src/docgen/story-docs-build.test.ts > buildStoryDocsPayload in component format > exposes the class the outlet template reads as a value
   → expected '<ng-container *ngComponentOutlet="But…' to be '@Component({\n  selector: \'app-root\…' // Object.is equality

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

  1. yarn task sandbox --template angular-vite/docgen-server-ts --start-from auto, then yarn storybook from the generated sandbox. That template is the Angular sandbox with experimentalDocgenServer and componentsManifest already on.
  2. Open Example/Button → Docs and press Show code. You should see the bare <sb-button …> element.
  3. Stop Storybook, set framework.options.snippetFormat to 'component' in the sandbox's .storybook/main.ts, and start it again.
  4. Press Show code on the same story. You should now see a full @Component({ … }) export class App block with a clicked method, instead of the bare element.
  5. Remove the option again and confirm the block goes back to the template fragment.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Declare whether manual QA will be needed for this PR during the next release, through qa:needed or qa:skip

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

@github-actions

github-actions Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor
Fails
🚫

PR is not labeled with one of: ["qa:needed","qa:skip","qa:success"]

Warnings
⚠️

This PR targets valentin/angular-story-docs-3-warning. The default branch for contributions is next. Please make sure you are targeting the correct branch.

Generated by 🚫 dangerJS against 4adc94c

@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-3-warning branch from 8ab3bd3 to ce7d9ad Compare August 7, 2026 16:40
@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-4-component-format branch from d1c9682 to e7b7901 Compare August 7, 2026 16:40
@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-3-warning branch from ce7d9ad to c0429f9 Compare August 7, 2026 16:43
@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-4-component-format branch from e7b7901 to f3992ed Compare August 7, 2026 16:43
@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-3-warning branch from c0429f9 to cbf6fcd Compare August 7, 2026 16:49
@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-4-component-format branch from f3992ed to c84623a Compare August 7, 2026 16:49
@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-3-warning branch from cbf6fcd to ce9df5d Compare August 7, 2026 17:01
@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-4-component-format branch from c84623a to 85c8dad Compare August 7, 2026 17:02
@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-3-warning branch from ce9df5d to d9dbeea Compare August 7, 2026 17:09
@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-4-component-format branch from 85c8dad to 10d63ea Compare August 7, 2026 17:09
@valentinpalkovic valentinpalkovic self-assigned this Aug 7, 2026
@valentinpalkovic valentinpalkovic added feature request ci:normal Run our default set of CI jobs (choose this for most PRs). labels Aug 7, 2026
Comment thread code/frameworks/angular-vite/src/docgen/component-snippet.ts Outdated
@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-4-component-format branch from 10d63ea to d1c740f Compare August 7, 2026 17:38
@valentinpalkovic
valentinpalkovic marked this pull request as ready for review August 7, 2026 17:43
@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e9035efe-dcca-4fec-a1bd-43cc17e4a48e

📥 Commits

Reviewing files that changed from the base of the PR and between 5e3d529 and be59091.

📒 Files selected for processing (1)
  • code/frameworks/angular-vite/src/docgen/story-docs-limitations.md

Walkthrough

Adds configurable Angular docgen snippet formats. Template remains the default. Component format emits standalone host components, imports, and output handlers. Preset wiring passes framework options. Tests and documentation cover format behavior.

Changes

Angular snippet formats

Layer / File(s) Summary
Snippet format configuration
code/frameworks/angular-vite/src/types.ts, code/frameworks/angular-vite/src/docgen/story-docs-preset.ts
Adds the SnippetFormat type and forwards snippetFormat from framework options into documentation generation.
Angular host-component generation
code/frameworks/angular-vite/src/docgen/component-snippet.ts, code/frameworks/angular-vite/src/docgen/component-snippet.test.ts
Generates host imports and standalone components with output handlers, outlet support, safe member names, and escaped template content.
Story documentation integration
code/frameworks/angular-vite/src/docgen/build-story-docs.ts, code/frameworks/angular-vite/src/docgen/build-story-docs.test.ts, code/frameworks/angular-vite/src/docgen/story-docs-limitations.md
Selects template or component output, tracks handlers and warnings, emits shared imports, and documents the supported formats.

Sequence Diagram(s)

sequenceDiagram
  participant StoryDocsPreset
  participant buildStoryDocs
  participant angularHostImports
  participant angularHostComponent
  participant StoryDocsOutput
  StoryDocsPreset->>buildStoryDocs: pass snippetFormat
  buildStoryDocs->>angularHostImports: build host imports
  angularHostImports-->>buildStoryDocs: return import block
  buildStoryDocs->>angularHostComponent: wrap template with handlers
  angularHostComponent-->>buildStoryDocs: return host component
  buildStoryDocs->>StoryDocsOutput: emit snippet and warnings
Loading

Possibly related PRs

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@code/frameworks/angular-vite/src/docgen/build-story-docs.ts`:
- Around line 408-410: Update the literal-template branch in the story-doc
generation flow to inspect supported host event and input expressions, declare
the required handlers or bindings on the generated host class, and preserve a
warning plus the reduced compile guarantee for unsupported expressions. Revise
the literal-template test that currently expects an empty host class to cover
these declarations and the unsupported-expression behavior.

In `@code/frameworks/angular-vite/src/docgen/component-snippet.ts`:
- Around line 46-50: Update the component snippet generation around handlers so
each output alias maps to a unique, safe host method identifier, and reuse that
mapping for both generated event-binding expressions and host members instead of
emitting aliases directly. Preserve output alias binding semantics, and add an
assertion covering the complete generated snippet for a non-identifier output
such as data-changed.
- Around line 25-31: Update component snippet generation around the import block
and angularHostComponent so locally declared components without context.importId
remain compilable when pasted independently. Emit a portable component
declaration or include the component source in the payload; alternatively reject
this unsupported mode before generating references to componentName. Update the
test covering absent component imports to assert the chosen behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 43ca5a9a-7b44-49c4-a2cc-b6e914e4221c

📥 Commits

Reviewing files that changed from the base of the PR and between d9dbeea and 5e3d529.

📒 Files selected for processing (7)
  • code/frameworks/angular-vite/src/docgen/build-story-docs.test.ts
  • code/frameworks/angular-vite/src/docgen/build-story-docs.ts
  • code/frameworks/angular-vite/src/docgen/component-snippet.test.ts
  • code/frameworks/angular-vite/src/docgen/component-snippet.ts
  • code/frameworks/angular-vite/src/docgen/story-docs-limitations.md
  • code/frameworks/angular-vite/src/docgen/story-docs-preset.ts
  • code/frameworks/angular-vite/src/types.ts

Comment on lines +408 to +410
if (template?.kind === 'literal') {
return { snippet: template.markup };
// Which outputs the story's own markup binds is not knowable, so the host declares none.
return { snippet: template.markup, handlers: [] };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Handle host expressions in literal templates.

This branch always returns no handlers. A literal template such as <sb-button (clicked)="clicked($event)"></sb-button> produces a host class without clicked, so the advertised standalone component does not compile. Input expressions can fail for the same reason.

Parse and declare supported host expressions, or attach a warning and limit the component-format compile guarantee to generated templates. Update the literal-template test that currently asserts an empty host class.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/frameworks/angular-vite/src/docgen/build-story-docs.ts` around lines 408
- 410, Update the literal-template branch in the story-doc generation flow to
inspect supported host event and input expressions, declare the required
handlers or bindings on the generated host class, and preserve a warning plus
the reduced compile guarantee for unsupported expressions. Revise the
literal-template test that currently expects an empty host class to cover these
declarations and the unsupported-expression behavior.

Comment on lines +25 to +31
...(context.importId
? [
context.defaultImport
? `import ${context.componentName} from '${context.importId}';`
: `import { ${context.componentName} } from '${context.importId}';`,
]
: []),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Emit a component definition for local story components.

When context.importId is absent, this block emits no componentName definition. angularHostComponent still emits imports: [componentName] or readonly componentName = componentName. The component-format snippet cannot compile when pasted outside the original story module.

Emit a portable component declaration or include its source in the payload. Otherwise, reject this mode for locally declared components. Update the test that expects no component import for this case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/frameworks/angular-vite/src/docgen/component-snippet.ts` around lines 25
- 31, Update component snippet generation around the import block and
angularHostComponent so locally declared components without context.importId
remain compilable when pasted independently. Emit a portable component
declaration or include the component source in the payload; alternatively reject
this unsupported mode before generating references to componentName. Update the
test covering absent component imports to assert the chosen behavior.

Comment on lines +46 to +50
const members = [
// `*ngComponentOutlet` reads the class as a template expression, so the host has to expose it.
...(context.outlet ? [`readonly ${context.componentName} = ${context.componentName};`] : []),
...handlers.map((name) => `${memberName(name)}(event: unknown) {}`),
];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Use safe host method identifiers for output bindings.

handlers contains output aliases, not safe template-expression identifiers. For an output named data-changed, this generates ['data-changed'](...) on the class, but generated markup calls data-changed($event). Angular parses that expression as subtraction, not as a method call.

Map each bound output to a unique safe host method name. Use that mapping when generating both the event binding expression and the host member. Add an assertion for the complete non-identifier output snippet.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/frameworks/angular-vite/src/docgen/component-snippet.ts` around lines 46
- 50, Update the component snippet generation around handlers so each output
alias maps to a unique, safe host method identifier, and reuse that mapping for
both generated event-binding expressions and host members instead of emitting
aliases directly. Preserve output alias binding semantics, and add an assertion
covering the complete generated snippet for a non-identifier output such as
data-changed.

@storybook-app-bot

storybook-app-bot Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Package Benchmarks

Commit: 4adc94c, ran on 10 August 2026 at 10:17:20 UTC

The following packages have significant changes to their size or dependencies:

@storybook/addon-a11y

Before After Difference
Dependency count 0 2 🚨 +2 🚨
Self size 0 B 188 KB 🚨 +188 KB 🚨
Dependency size 0 B 3.12 MB 🚨 +3.12 MB 🚨
Bundle Size Analyzer Link Link

@storybook/addon-docs

Before After Difference
Dependency count 0 18 🚨 +18 🚨
Self size 0 B 1.29 MB 🚨 +1.29 MB 🚨
Dependency size 0 B 9.28 MB 🚨 +9.28 MB 🚨
Bundle Size Analyzer Link Link

@storybook/addon-links

Before After Difference
Dependency count 0 1 🚨 +1 🚨
Self size 0 B 14 KB 🚨 +14 KB 🚨
Dependency size 0 B 5 KB 🚨 +5 KB 🚨
Bundle Size Analyzer Link Link

@storybook/addon-mcp

Before After Difference
Dependency count 0 13 🚨 +13 🚨
Self size 0 B 191 KB 🚨 +191 KB 🚨
Dependency size 0 B 2.79 MB 🚨 +2.79 MB 🚨
Bundle Size Analyzer Link Link

@storybook/addon-onboarding

Before After Difference
Dependency count 0 0 0
Self size 0 B 332 KB 🚨 +332 KB 🚨
Dependency size 0 B 670 B 🚨 +670 B 🚨
Bundle Size Analyzer Link Link

storybook-addon-pseudo-states

Before After Difference
Dependency count 0 0 0
Self size 0 B 21 KB 🚨 +21 KB 🚨
Dependency size 0 B 689 B 🚨 +689 B 🚨
Bundle Size Analyzer Link Link

@storybook/addon-themes

Before After Difference
Dependency count 0 1 🚨 +1 🚨
Self size 0 B 18 KB 🚨 +18 KB 🚨
Dependency size 0 B 28 KB 🚨 +28 KB 🚨
Bundle Size Analyzer Link Link

@storybook/addon-vitest

Before After Difference
Dependency count 0 2 🚨 +2 🚨
Self size 0 B 429 KB 🚨 +429 KB 🚨
Dependency size 0 B 350 KB 🚨 +350 KB 🚨
Bundle Size Analyzer Link Link

@storybook/builder-vite

Before After Difference
Dependency count 0 11 🚨 +11 🚨
Self size 0 B 136 KB 🚨 +136 KB 🚨
Dependency size 0 B 1.32 MB 🚨 +1.32 MB 🚨
Bundle Size Analyzer Link Link

@storybook/builder-webpack5

Before After Difference
Dependency count 0 186 🚨 +186 🚨
Self size 0 B 79 KB 🚨 +79 KB 🚨
Dependency size 0 B 35.76 MB 🚨 +35.76 MB 🚨
Bundle Size Analyzer Link Link

storybook

Before After Difference
Dependency count 0 73 🚨 +73 🚨
Self size 0 B 21.47 MB 🚨 +21.47 MB 🚨
Dependency size 0 B 31.24 MB 🚨 +31.24 MB 🚨
Bundle Size Analyzer Link Link

@storybook/angular

Before After Difference
Dependency count 0 185 🚨 +185 🚨
Self size 0 B 255 KB 🚨 +255 KB 🚨
Dependency size 0 B 30.17 MB 🚨 +30.17 MB 🚨
Bundle Size Analyzer Link Link

@storybook/angular-vite

Before After Difference
Dependency count 0 29 🚨 +29 🚨
Self size 0 B 23.11 MB 🚨 +23.11 MB 🚨
Dependency size 0 B 12.68 MB 🚨 +12.68 MB 🚨
Bundle Size Analyzer Link Link

@storybook/ember

Before After Difference
Dependency count 0 185 🚨 +185 🚨
Self size 0 B 13 KB 🚨 +13 KB 🚨
Dependency size 0 B 31.11 MB 🚨 +31.11 MB 🚨
Bundle Size Analyzer Link Link

@storybook/html-vite

Before After Difference
Dependency count 0 14 🚨 +14 🚨
Self size 0 B 22 KB 🚨 +22 KB 🚨
Dependency size 0 B 1.49 MB 🚨 +1.49 MB 🚨
Bundle Size Analyzer Link Link

@storybook/nextjs

Before After Difference
Dependency count 0 531 🚨 +531 🚨
Self size 0 B 641 KB 🚨 +641 KB 🚨
Dependency size 0 B 62.45 MB 🚨 +62.45 MB 🚨
Bundle Size Analyzer Link Link

@storybook/nextjs-vite

Before After Difference
Dependency count 0 94 🚨 +94 🚨
Self size 0 B 1.42 MB 🚨 +1.42 MB 🚨
Dependency size 0 B 23.86 MB 🚨 +23.86 MB 🚨
Bundle Size Analyzer Link Link

@storybook/preact-vite

Before After Difference
Dependency count 0 14 🚨 +14 🚨
Self size 0 B 12 KB 🚨 +12 KB 🚨
Dependency size 0 B 1.51 MB 🚨 +1.51 MB 🚨
Bundle Size Analyzer Link Link

@storybook/react-native-web-vite

Before After Difference
Dependency count 0 125 🚨 +125 🚨
Self size 0 B 29 KB 🚨 +29 KB 🚨
Dependency size 0 B 25.84 MB 🚨 +25.84 MB 🚨
Bundle Size Analyzer Link Link

@storybook/react-vite

Before After Difference
Dependency count 0 83 🚨 +83 🚨
Self size 0 B 32 KB 🚨 +32 KB 🚨
Dependency size 0 B 21.17 MB 🚨 +21.17 MB 🚨
Bundle Size Analyzer Link Link

@storybook/react-webpack5

Before After Difference
Dependency count 0 272 🚨 +272 🚨
Self size 0 B 23 KB 🚨 +23 KB 🚨
Dependency size 0 B 48.20 MB 🚨 +48.20 MB 🚨
Bundle Size Analyzer Link Link

@storybook/server-webpack5

Before After Difference
Dependency count 0 198 🚨 +198 🚨
Self size 0 B 15 KB 🚨 +15 KB 🚨
Dependency size 0 B 37.03 MB 🚨 +37.03 MB 🚨
Bundle Size Analyzer Link Link

@storybook/svelte-vite

Before After Difference
Dependency count 0 20 🚨 +20 🚨
Self size 0 B 54 KB 🚨 +54 KB 🚨
Dependency size 0 B 26.65 MB 🚨 +26.65 MB 🚨
Bundle Size Analyzer Link Link

@storybook/sveltekit

Before After Difference
Dependency count 0 21 🚨 +21 🚨
Self size 0 B 56 KB 🚨 +56 KB 🚨
Dependency size 0 B 26.71 MB 🚨 +26.71 MB 🚨
Bundle Size Analyzer Link Link

@storybook/tanstack-react

Before After Difference
Dependency count 0 84 🚨 +84 🚨
Self size 0 B 118 KB 🚨 +118 KB 🚨
Dependency size 0 B 21.20 MB 🚨 +21.20 MB 🚨
Bundle Size Analyzer Link Link

@storybook/vue3-vite

Before After Difference
Dependency count 0 103 🚨 +103 🚨
Self size 0 B 31 KB 🚨 +31 KB 🚨
Dependency size 0 B 19.59 MB 🚨 +19.59 MB 🚨
Bundle Size Analyzer Link Link

@storybook/web-components-vite

Before After Difference
Dependency count 0 15 🚨 +15 🚨
Self size 0 B 19 KB 🚨 +19 KB 🚨
Dependency size 0 B 1.55 MB 🚨 +1.55 MB 🚨
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 0 205 🚨 +205 🚨
Self size 0 B 833 KB 🚨 +833 KB 🚨
Dependency size 0 B 86.21 MB 🚨 +86.21 MB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 0 198 🚨 +198 🚨
Self size 0 B 32 KB 🚨 +32 KB 🚨
Dependency size 0 B 84.69 MB 🚨 +84.69 MB 🚨
Bundle Size Analyzer Link Link

@storybook/core-webpack

Before After Difference
Dependency count 0 1 🚨 +1 🚨
Self size 0 B 11 KB 🚨 +11 KB 🚨
Dependency size 0 B 28 KB 🚨 +28 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 0 74 🚨 +74 🚨
Self size 0 B 1.09 MB 🚨 +1.09 MB 🚨
Dependency size 0 B 52.71 MB 🚨 +52.71 MB 🚨
Bundle Size Analyzer node node

@storybook/csf-plugin

Before After Difference
Dependency count 0 9 🚨 +9 🚨
Self size 0 B 7 KB 🚨 +7 KB 🚨
Dependency size 0 B 1.28 MB 🚨 +1.28 MB 🚨
Bundle Size Analyzer Link Link

eslint-plugin-storybook

Before After Difference
Dependency count 0 20 🚨 +20 🚨
Self size 0 B 137 KB 🚨 +137 KB 🚨
Dependency size 0 B 3.04 MB 🚨 +3.04 MB 🚨
Bundle Size Analyzer Link Link

@storybook/mcp

Before After Difference
Dependency count 0 11 🚨 +11 🚨
Self size 0 B 107 KB 🚨 +107 KB 🚨
Dependency size 0 B 2.64 MB 🚨 +2.64 MB 🚨
Bundle Size Analyzer Link Link

@storybook/react-dom-shim

Before After Difference
Dependency count 0 0 0
Self size 0 B 19 KB 🚨 +19 KB 🚨
Dependency size 0 B 1 KB 🚨 +1 KB 🚨
Bundle Size Analyzer Link Link

@storybook/preset-create-react-app

Before After Difference
Dependency count 0 68 🚨 +68 🚨
Self size 0 B 32 KB 🚨 +32 KB 🚨
Dependency size 0 B 6.07 MB 🚨 +6.07 MB 🚨
Bundle Size Analyzer Link Link

@storybook/preset-react-webpack

Before After Difference
Dependency count 0 161 🚨 +161 🚨
Self size 0 B 19 KB 🚨 +19 KB 🚨
Dependency size 0 B 32.73 MB 🚨 +32.73 MB 🚨
Bundle Size Analyzer Link Link

@storybook/preset-server-webpack

Before After Difference
Dependency count 0 10 🚨 +10 🚨
Self size 0 B 7 KB 🚨 +7 KB 🚨
Dependency size 0 B 1.20 MB 🚨 +1.20 MB 🚨
Bundle Size Analyzer Link Link

@storybook/html

Before After Difference
Dependency count 0 2 🚨 +2 🚨
Self size 0 B 29 KB 🚨 +29 KB 🚨
Dependency size 0 B 33 KB 🚨 +33 KB 🚨
Bundle Size Analyzer Link Link

@storybook/preact

Before After Difference
Dependency count 0 2 🚨 +2 🚨
Self size 0 B 47 KB 🚨 +47 KB 🚨
Dependency size 0 B 33 KB 🚨 +33 KB 🚨
Bundle Size Analyzer Link Link

@storybook/react

Before After Difference
Dependency count 0 59 🚨 +59 🚨
Self size 0 B 1.45 MB 🚨 +1.45 MB 🚨
Dependency size 0 B 12.26 MB 🚨 +12.26 MB 🚨
Bundle Size Analyzer Link Link

@storybook/server

Before After Difference
Dependency count 0 3 🚨 +3 🚨
Self size 0 B 9 KB 🚨 +9 KB 🚨
Dependency size 0 B 719 KB 🚨 +719 KB 🚨
Bundle Size Analyzer Link Link

@storybook/svelte

Before After Difference
Dependency count 0 3 🚨 +3 🚨
Self size 0 B 49 KB 🚨 +49 KB 🚨
Dependency size 0 B 601 KB 🚨 +601 KB 🚨
Bundle Size Analyzer Link Link

@storybook/vue3

Before After Difference
Dependency count 0 91 🚨 +91 🚨
Self size 0 B 103 KB 🚨 +103 KB 🚨
Dependency size 0 B 18.14 MB 🚨 +18.14 MB 🚨
Bundle Size Analyzer Link Link

@storybook/web-components

Before After Difference
Dependency count 0 3 🚨 +3 🚨
Self size 0 B 80 KB 🚨 +80 KB 🚨
Dependency size 0 B 48 KB 🚨 +48 KB 🚨
Bundle Size Analyzer Link Link

@valentinpalkovic valentinpalkovic removed the ci:normal Run our default set of CI jobs (choose this for most PRs). label Aug 7, 2026
@valentinpalkovic
valentinpalkovic marked this pull request as draft August 8, 2026 05:36
@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-3-warning branch from f3061fa to 3d41670 Compare August 8, 2026 05:42
A bare template fragment reads fine beside a rendered story, but it cannot be
pasted anywhere: an Angular template only exists inside a component, and an
agent handed one has to guess the rest.

`framework.options.snippetFormat: 'component'` wraps the same markup in the
standalone host it needs to compile, and the payload carries the matching
import block. `'template'` stays the default, so both shapes remain available.

The host declares a no-op method per output the markup actually binds, because
Angular's template type checking resolves `(clicked)="clicked($event)"` against
the host class. Which outputs those are is read back off the emitted markup, so
a story that wrote its own wrapper around `argsToTemplate(args, { exclude })`
gets exactly the handlers that survived the filter, and one that wrote plain
markup gets none.
@valentinpalkovic
valentinpalkovic force-pushed the valentin/angular-story-docs-4-component-format branch from be59091 to 3a0d785 Compare August 8, 2026 06:02
@valentinpalkovic valentinpalkovic added the ci:normal Run our default set of CI jobs (choose this for most PRs). label Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:normal Run our default set of CI jobs (choose this for most PRs). feature request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant