feat(storybook): add @fluentui/react-storybook-addon-playground with in-browser TSX playground (#36728) - #36744
Dmytro Kirpa (dmytrokirpa) wants to merge 23 commits into
Conversation
…in-browser TSX playground (#36728) Co-authored-by: Cursor <cursoragent@cursor.com>
📊 Bundle size report✅ No changes found |
There was a problem hiding this comment.
🟡 Changes recommended
Runtime correctness, accessibility, peer-version, CSS transformation, and release metadata issues remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds a configurable Storybook addon providing an in-browser Monaco TSX playground, sandboxed preview, typings, formatting, and shareable state.
Changes:
- Implements the playground shell, runtime, compiler, and Storybook integration.
- Adds tests, public APIs, documentation, and build configuration.
- Enables the addon for headless-component Storybook and docsite builds.
File summaries
| File | Description |
|---|---|
.github/CODEOWNERS |
Assigns addon ownership. |
apps/public-docsite-v9-headless/package.json |
Adds the addon dependency. |
apps/public-docsite-v9-headless/project.json |
Adds build dependencies. |
change/@fluentui-react-storybook-addon-export-to-sandbox-bfb6dbfb-a9e5-47e0-b04d-be8d1f1d4399.json |
Records sandbox-addon fix. |
change/@fluentui-react-storybook-addon-playground-99650265-91f2-458b-bfdb-cf5dda68c498.json |
Records playground package change. |
packages/react-components/react-headless-components-preview/stories/.storybook/css.d.ts |
Declares CSS imports. |
packages/react-components/react-headless-components-preview/stories/.storybook/main.js |
Configures playground modules and setup. |
packages/react-components/react-headless-components-preview/stories/.storybook/playground.setup.tsx |
Defines headless playground presentation. |
packages/react-components/react-headless-components-preview/stories/.storybook/preview.js |
Loads addon styling. |
packages/react-components/react-headless-components-preview/stories/.storybook/tsconfig.json |
Includes setup sources. |
packages/react-components/react-headless-components-preview/stories/project.json |
Adds Storybook build prerequisites. |
packages/react-components/react-storybook-addon-export-to-sandbox/src/sandbox-utils.ts |
Excludes playground buttons from lookup. |
packages/react-components/react-storybook-addon-playground/.babelrc.json |
Configures Babel transforms. |
packages/react-components/react-storybook-addon-playground/.swcrc |
Excludes separately bundled sources. |
packages/react-components/react-storybook-addon-playground/LICENSE |
Adds package license. |
packages/react-components/react-storybook-addon-playground/README.md |
Documents installation and usage. |
packages/react-components/react-storybook-addon-playground/config/api-extractor.json |
Configures API extraction. |
packages/react-components/react-storybook-addon-playground/config/tests.js |
Adds Jest setup. |
packages/react-components/react-storybook-addon-playground/eslint.config.js |
Configures React and DOM linting. |
packages/react-components/react-storybook-addon-playground/etc/react-storybook-addon-playground.api.md |
Records public API surface. |
packages/react-components/react-storybook-addon-playground/jest.config.js |
Configures unit tests. |
packages/react-components/react-storybook-addon-playground/package.json |
Adds dependencies and exports. |
packages/react-components/react-storybook-addon-playground/preset.js |
Serves playground assets. |
packages/react-components/react-storybook-addon-playground/project.json |
Adds playground build target. |
packages/react-components/react-storybook-addon-playground/src/decorators/withOpenInPlaygroundButton.spec.ts |
Tests Docs button integration. |
packages/react-components/react-storybook-addon-playground/src/decorators/withOpenInPlaygroundButton.ts |
Adds the Docs launcher button. |
packages/react-components/react-storybook-addon-playground/src/defaultSetup.tsx |
Defines default Fluent setup. |
packages/react-components/react-storybook-addon-playground/src/index.ts |
Exports public APIs. |
packages/react-components/react-storybook-addon-playground/src/playground/Editor.styles.ts |
Styles the editor container. |
packages/react-components/react-storybook-addon-playground/src/playground/Editor.tsx |
Integrates Monaco models and actions. |
packages/react-components/react-storybook-addon-playground/src/playground/Playground.styles.ts |
Styles the playground shell. |
packages/react-components/react-storybook-addon-playground/src/playground/Playground.tsx |
Implements the main playground UI. |
packages/react-components/react-storybook-addon-playground/src/playground/Preview.styles.ts |
Styles the preview frame. |
packages/react-components/react-storybook-addon-playground/src/playground/Preview.tsx |
Coordinates the sandboxed preview. |
packages/react-components/react-storybook-addon-playground/src/playground/compiler.ts |
Compiles TSX through Monaco. |
packages/react-components/react-storybook-addon-playground/src/playground/cssModules.spec.ts |
Tests CSS-module processing. |
packages/react-components/react-storybook-addon-playground/src/playground/cssModules.ts |
Transforms CSS-module sources. |
packages/react-components/react-storybook-addon-playground/src/playground/editorTheme.ts |
Defines Monaco themes. |
packages/react-components/react-storybook-addon-playground/src/playground/formatter.spec.ts |
Tests Prettier integration. |
packages/react-components/react-storybook-addon-playground/src/playground/formatter.ts |
Registers document formatters. |
packages/react-components/react-storybook-addon-playground/src/playground/main.tsx |
Bootstraps the standalone app. |
packages/react-components/react-storybook-addon-playground/src/playground/monaco.ts |
Configures Monaco and workers. |
packages/react-components/react-storybook-addon-playground/src/playground/playground.html |
Provides the shell document. |
packages/react-components/react-storybook-addon-playground/src/playground/runner.spec.ts |
Tests module validation. |
packages/react-components/react-storybook-addon-playground/src/playground/runner.ts |
Validates compiled imports. |
packages/react-components/react-storybook-addon-playground/src/playground/runtime.ts |
Loads and resolves runtime manifests. |
packages/react-components/react-storybook-addon-playground/src/playground/sandbox.ts |
Builds the isolated execution document. |
packages/react-components/react-storybook-addon-playground/src/playground/shortcuts.spec.ts |
Tests shortcut labels. |
packages/react-components/react-storybook-addon-playground/src/playground/shortcuts.ts |
Provides platform shortcuts. |
packages/react-components/react-storybook-addon-playground/src/playground/themes.ts |
Defines shell themes. |
packages/react-components/react-storybook-addon-playground/src/playground/typings.ts |
Registers Monaco declarations. |
packages/react-components/react-storybook-addon-playground/src/playground/useMediaQuery.ts |
Tracks responsive queries. |
packages/react-components/react-storybook-addon-playground/src/playground/useSplitPane.spec.ts |
Tests split-pane behavior. |
packages/react-components/react-storybook-addon-playground/src/playground/useSplitPane.ts |
Implements pane resizing. |
packages/react-components/react-storybook-addon-playground/src/preset/preset.ts |
Exposes the Webpack hook. |
packages/react-components/react-storybook-addon-playground/src/preset/preview.ts |
Registers the decorator. |
packages/react-components/react-storybook-addon-playground/src/public-types.ts |
Defines addon configuration types. |
packages/react-components/react-storybook-addon-playground/src/setup.ts |
Defines setup and manifest APIs. |
packages/react-components/react-storybook-addon-playground/src/styles.css |
Styles the Docs launcher. |
packages/react-components/react-storybook-addon-playground/src/types.ts |
Extends Storybook context types. |
packages/react-components/react-storybook-addon-playground/src/url.spec.ts |
Tests URL-state handling. |
packages/react-components/react-storybook-addon-playground/src/url.ts |
Encodes shareable playground state. |
packages/react-components/react-storybook-addon-playground/src/webpack.spec.ts |
Tests runtime-entry generation. |
packages/react-components/react-storybook-addon-playground/src/webpack.ts |
Emits runtime assets and typings. |
packages/react-components/react-storybook-addon-playground/tools/collect-typings.js |
Collects transitive declarations. |
packages/react-components/react-storybook-addon-playground/tools/collect-typings.spec.js |
Tests declaration collection. |
packages/react-components/react-storybook-addon-playground/tsconfig.json |
References playground compilation. |
packages/react-components/react-storybook-addon-playground/tsconfig.lib.json |
Excludes bundled playground files. |
packages/react-components/react-storybook-addon-playground/tsconfig.playground.json |
Configures shell type checking. |
packages/react-components/react-storybook-addon-playground/tsconfig.spec.json |
Configures test type checking. |
packages/react-components/react-storybook-addon-playground/webpack.playground.config.js |
Bundles the standalone shell. |
syncpack.config.js |
Preserves Monaco version policy. |
tsconfig.base.all.json |
Adds the workspace package alias. |
tsconfig.base.json |
Adds the package path mapping. |
yarn.lock |
Records workspace dependencies. |
Review details
- Files reviewed: 63/65 changed files
- Comments generated: 11
- Review effort level: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Pull request demo site: URL |
There was a problem hiding this comment.
🟡 Changes recommended
Cross-platform option discovery, CSS error handling, subpath typings, token usage, and forced-colors focus visibility remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (3)
Previously missed (3) — in code that hasn't changed since the last review.
packages/react-components/react-storybook-addon-playground/package.json:52
- The
./setupsubpath resolves types from the root declaration barrel but runtime values fromlib/setup.js. This makes root-only values such ascreatePlaygroundUrlappear importable from@fluentui/react-storybook-addon-playground/setup, although that runtime module does not export them. Point the types condition at the declaration generated fromsetup.ts.
packages/react-components/react-storybook-addon-playground/src/styles.css:27 - Removing the outline leaves this box shadow as the only keyboard-focus indicator. Box shadows are suppressed in Windows forced-colors mode, so the new button can have no visible focus state there; retain a solid outline (or add an explicit forced-colors rule) instead.
packages/react-components/react-storybook-addon-playground/src/playground/Playground.styles.ts:40 - The new shell stylesheet hardcodes spacing and typography values throughout (for example
16pxhere) even though it is rendered underFluentProvider.docs/architecture/design-tokens.md:3-19requires tokens for spacing, fonts, radii, strokes, and durations so these values remain theme-consistent. Replace the themeable literals across this stylesheet with the corresponding Fluent tokens.
- Files reviewed: 72/74 changed files
- Comments generated: 2
- Review effort level: Balanced
Compile initial CSS through the guarded debounced run path so malformed shared playground CSS reports an error instead of throwing during React render.
There was a problem hiding this comment.
🟡 Changes recommended
URL-state loss, declaration-resolution failures, an inconsistent subpath API, and accessibility issues remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (6)
Previously missed (6) — in code that hasn't changed since the last review.
packages/react-components/react-storybook-addon-playground/src/playground/Playground.tsx:676
- This hint is false after a component render error. The sandbox replaces the previous tree with a new keyed error boundary, whose error state renders
null, so a previously successful preview becomes blank while this message says it is still shown. Either preserve the prior element on sandbox render failures or track whether each error occurred beforeroot.renderand only show this hint when the old preview was retained.
packages/react-components/react-storybook-addon-playground/src/styles.css:29 - Removing the native outline leaves this button with only a box-shadow focus indicator. Forced-colors mode suppresses box shadows, so keyboard focus becomes invisible. Keep an outline (it can be transparent normally and use
Highlightin forced colors) in addition to the visual inset treatment.
packages/react-components/react-storybook-addon-playground/src/url.ts:35 decodeCodeis not the inverse ofencodeCodefor a valid empty source: decodingencodeCode('')yields'', which this line turns intonull.decodePlaygroundStateFromHashthen rejects it andPlaygroundalso skips hash synchronization for empty code, so clearing the editor and refreshing/share-linking restores the default or previous source instead of the current empty program. Preserve empty strings and update the downstream truthiness checks to distinguish onlynull.
packages/react-components/react-storybook-addon-playground/tools/collect-typings.js:16- This regex also recognizes import-like text inside comments and string literals. A declaration JSDoc example such as
// import { Example } from 'optional-package'is treated as a real bare dependency; unlike unresolved relative false positives, it is added tomissingand fails the Storybook build. Extract specifiers from parsed syntax or lexically skip comments and quoted text before matching.
packages/react-components/react-storybook-addon-playground/tools/collect-typings.js:260 - Packages that publish declarations only through
package.json#exportsare rejected here because own-type detection checks only top-leveltypes/typingsandindex.d.ts. AlthoughresolveEntryFilesupports exports maps, it is never reached for such a package, so a configured modern package is reported as missing and the Storybook build fails. Include resolvable export type targets in this detection while retaining the@types/*fallback.
packages/react-components/react-storybook-addon-playground/src/playground/Playground.styles.ts:40 - These new shell styles hardcode spacing and stroke values even though
docs/architecture/design-tokens.md:5-19requires Fluent tokens for spacing, borders, typography, radii, and durations. Replace values such as the 16px gap/padding and 1px stroke withtokens.spacingHorizontalMandtokens.strokeWidthThin, and apply the same tokenization to the other semantic values in this stylesheet so theme/high-contrast behavior remains consistent.
- Files reviewed: 72/74 changed files
- Comments generated: 2
- Review effort level: Balanced
Generate isolated declarations for the setup subpath and add component-level coverage for successful, failed, and stale playground compile transactions.
|
Copilot Fix the code for all comments in this review thread. When a review comment includes a suggested change, apply the suggestion exactly. Do not make changes beyond what is described in the linked review thread. |
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
Fixed the linked review finding in |
There was a problem hiding this comment.
🟡 Changes recommended
Several headless stories currently open broken playgrounds due to unsupported imports, with additional URL-state and runtime edge cases unresolved.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 75/77 changed files
- Comments generated: 6
- Review effort level: Balanced
| loadWorkspaceAddon('@fluentui/react-storybook-addon-playground', { | ||
| tsConfigPath, | ||
| /** @type {import('../../../react-storybook-addon-playground/src/index').PresetConfig} */ | ||
| options: { | ||
| modules: getHeadlessPlaygroundModules(), | ||
| setup: path.resolve(__dirname, './playground.setup.tsx'), | ||
| }, |
| const decoded = decompressFromEncodedURIComponent(encoded); | ||
|
|
||
| return typeof decoded === 'string' && decoded.length > 0 ? decoded : null; |
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
Reset behavior, stale asynchronous error attribution, alias typings, focus visibility, and release metadata need correction.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (4)
Previously missed (4) — in code that hasn't changed since the last review.
packages/react-components/react-storybook-addon-playground/src/playground/Playground.tsx:408
- Reset prefers the setup's generic
defaultCodeover the source that opened this playground. Because the built-in setup always providesdefaultCode, clicking “Reset” on any Docs story replaces that story with the generic demo instead of restoring its initial source. Match the initialization precedence by usinginitialCodefirst.
packages/react-components/react-storybook-addon-playground/src/styles.css:29 - Removing the outline and relying only on a colored inset shadow makes keyboard focus disappear in forced-colors/high-contrast modes, where author shadows can be suppressed. Preserve a native focus-visible outline for this button.
packages/react-components/react-storybook-addon-playground/src/webpack.ts:216 - The generated alias declaration only forwards named exports; TypeScript's
export *never forwards a default export. A configured mapping such as{ alias: 'default-exporting-package' }therefore works in the runtime loader but Monaco incorrectly reports thataliashas no default export. Generate alias typings that preserve the target module's complete export shape.
change/@fluentui-react-storybook-addon-playground-751293a3-5a89-42e3-8d5d-f2e4b6b20f94.json:2 - This change entry describes a feature but classifies it as
patch. Repository release guidance requiresminorfor features (docs/workflows/contributing.md:30-36), so this entry should use the feature release type as the other playground entry does.
- Files reviewed: 78/80 changed files
- Comments generated: 2
- Review effort level: Balanced
| if (runtimeError.runId === currentRunId) { | ||
| setError({ | ||
| title: runtimeErrorTitle(runtimeError.kind), | ||
| message: runtimeError.message, | ||
| previewRetained: false, | ||
| }); |
| const error = 'reason' in event ? event.reason : event.error || event.message; | ||
| sendError(error, activeRunId); |
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
Co-authored-by: dmytrokirpa <1492102+dmytrokirpa@users.noreply.github.com>
Previous Behavior
New Behavior
Related Issue(s)