Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
a0ee09e
feat: hide the reset zoom button when at the initial zoom level inste…
superLipbalm Jan 24, 2026
b04ffe2
refactor: adjust whitespace in zoom reset button style property
superLipbalm Jan 25, 2026
bbd480e
refactor: Conditionally render the zoom reset button instead of toggl…
superLipbalm Jan 26, 2026
7121f74
Fix Edit JSON button accessibility on small screens (WCAG 2.1 Reflow)
TheSeydiCharyyev Jan 29, 2026
e5efb51
Add gap between icon and text in Edit JSON button
TheSeydiCharyyev Jan 29, 2026
2c3c4bd
fix: restore absolute positioning for Edit JSON button on large scree…
TheSeydiCharyyev Feb 10, 2026
310a764
Add small viewport stories for Chromatic coverage
TheSeydiCharyyev Feb 10, 2026
fba3173
Add origin validation to websocket connections
ghengeveld Feb 11, 2026
8ec43fd
Update supported versions and security patching details
vanessayuenn Feb 13, 2026
4025b7b
Update security policy for version support and backporting
vanessayuenn Feb 13, 2026
f45870f
refactor: use sr-only styles instead of display:none and add containe…
TheSeydiCharyyev Feb 20, 2026
45eda44
Initial plan
Copilot Feb 20, 2026
f48a1ae
Fix ConfigFile parser warning on definePreview({...}).type<T>() chaining
Copilot Feb 20, 2026
ed53d50
fix: Update TagOptions to allow undefined defaultFilterSelection and …
unional Feb 21, 2026
ed5064e
fix(manager-api): correctly resolve iframe.html URL when hosted at a …
Feb 21, 2026
08bdbd9
Merge branch 'next' into origin-validation
ghengeveld Feb 23, 2026
f095cf7
Refactor origin validation to accept allowedHosts option and allow ac…
ghengeveld Feb 24, 2026
4670245
fix: sort imports alphabetically in Object.tsx
TheSeydiCharyyev Feb 25, 2026
63c7cf9
Object: Fix up layout issues
Sidnioulz Feb 25, 2026
57d1759
Implement allowedHosts configuration for WebSocket connections, updat…
ghengeveld Feb 25, 2026
8d5be84
Apply suggestions from code review
vanessayuenn Feb 25, 2026
ff1c24a
Merge branch 'next' into vanessayuenn-patch-1
vanessayuenn Feb 25, 2026
601bd11
Merge branch 'next' into fix/issue-33848
valentinpalkovic Feb 25, 2026
9e48ac1
Initial plan
Copilot Feb 25, 2026
a20381d
docs: add TableOfContents API reference and update available blocks list
Copilot Feb 25, 2026
ba31175
Restore config
ghengeveld Feb 25, 2026
547521b
feat: Introduce a `hidden` prop to the `Button` component and utilize…
superLipbalm Feb 26, 2026
bd03936
Add host-validation-middleware to enhance WebSocket security and vali…
ghengeveld Feb 26, 2026
453de79
Refactor host validation logic and introduce token validation
ghengeveld Feb 26, 2026
0b1085f
Update docs/api/doc-blocks/doc-block-tableofcontents.mdx
valentinpalkovic Feb 27, 2026
862feb6
Update docs/api/doc-blocks/doc-block-tableofcontents.mdx
valentinpalkovic Feb 27, 2026
78dfb58
Update docs/api/doc-blocks/doc-block-tableofcontents.mdx
valentinpalkovic Feb 27, 2026
88ba63b
Resolve comments
ghengeveld Feb 27, 2026
90606b5
Merge branch 'next' into origin-validation
ghengeveld Feb 27, 2026
307e283
Remove TypeScript error suppression for private method access in serv…
ghengeveld Feb 27, 2026
5ffc0e1
UI: Rework edit button with instructions from MA
Sidnioulz Feb 27, 2026
9a50bb5
Remove bad config
ghengeveld Feb 27, 2026
72138ab
Docs: Mention React version requirement for addons
Sidnioulz Jan 21, 2026
48bea3f
Apply suggestion from @jonniebigodes
Sidnioulz Feb 27, 2026
340802e
Update getHostValidationMiddleware tests to use empty allowedHosts ar…
ghengeveld Feb 27, 2026
e2d16ff
Revert "feat: Introduce a `hidden` prop to the `Button` component and…
superLipbalm Feb 28, 2026
db26045
fix(manager-api): update refs sequentially in experimental_setFilter
ia319 Feb 28, 2026
2952d6b
Refactor: Replace conditional rendering of the zoom reset button with…
superLipbalm Feb 28, 2026
93f30d9
feat: use `hidden` attribute instead of `aria-hidden` for the zoom re…
superLipbalm Mar 1, 2026
2dc2b04
Revert "feat: use `hidden` attribute instead of `aria-hidden` for the…
superLipbalm Mar 2, 2026
bf19c7b
Merge pull request #33610 from storybookjs/sidnioulz/docs-addon-react…
Sidnioulz Mar 2, 2026
1129728
Merge branch 'next' into fix/issue-24149-edit-json-button-accessibility
Sidnioulz Mar 2, 2026
06617d7
Allow more direct operation of Zoom tool
Sidnioulz Jan 9, 2026
3bec845
Fix type issues in story file
Sidnioulz Mar 2, 2026
a0cf4dc
Adjust stories to new zoom range
Sidnioulz Mar 2, 2026
e5f1a60
Fix Zoom stories
Sidnioulz Mar 2, 2026
e299156
refactor
Sidnioulz Mar 2, 2026
b7355d8
Update CHANGELOG.md for v10.2.14 [skip ci]
storybook-bot Mar 2, 2026
109f76f
docs: add draftMode example to headers mock snippet
createhb21 Mar 2, 2026
52873a9
Merge pull request #33842 from storybookjs/vanessayuenn-patch-1
valentinpalkovic Mar 2, 2026
105ea58
Merge branch 'next' into docs/nextjs-draftmode-mock-example
jonniebigodes Mar 2, 2026
b4ba7cd
Merge pull request #33968 from createhb21/docs/nextjs-draftmode-mock-…
jonniebigodes Mar 2, 2026
498b913
Handle edge cases of zoomBy
Sidnioulz Mar 2, 2026
9cbeb3b
Merge pull request #33707 from TheSeydiCharyyev/fix/issue-24149-edit-…
Sidnioulz Mar 2, 2026
c4d647b
Merge pull request #33958 from ia319/bug/33800-update-refs-sequentially
valentinpalkovic Mar 2, 2026
344ac52
Merge pull request #33896 from danielalanbates/fix/issue-33848
valentinpalkovic Mar 3, 2026
558bede
Merge pull request #33635 from superLipbalm/fix/33614-hide-reset-butt…
Sidnioulz Mar 3, 2026
804b239
Remove test
valentinpalkovic Mar 3, 2026
4da62d2
Merge branch 'next' into storybook-config-tags
valentinpalkovic Mar 3, 2026
0e17410
Merge branch 'next' into copilot/fix-configfile-parser-warning
valentinpalkovic Mar 3, 2026
2bdb54a
Fix prettier formatting in ConfigFile.ts
Copilot Mar 3, 2026
1a6a7a1
Merge branch 'next-release' into next
storybook-bot Mar 3, 2026
993bc00
Remove unused 'server' preset and its interface
ghengeveld Mar 3, 2026
011e081
Merge pull request #33885 from storybookjs/copilot/fix-configfile-par…
valentinpalkovic Mar 3, 2026
fe92192
Merge pull request #33934 from storybookjs/copilot/update-table-of-co…
valentinpalkovic Mar 3, 2026
349399d
Merge pull request #33895 from unional/storybook-config-tags
valentinpalkovic Mar 3, 2026
dd5bfac
Show allowed hosts in starup information
ghengeveld Mar 3, 2026
ca17758
Handle review feedback
ghengeveld Mar 3, 2026
c7de8a8
Merge branch 'next' into origin-validation
ghengeveld Mar 3, 2026
7284b33
Merge pull request #33835 from storybookjs/origin-validation
ghengeveld Mar 3, 2026
9cd5156
Merge pull request #33496 from storybookjs/zoom-tool-kb-extras
Sidnioulz Mar 3, 2026
efbc16e
Fix copilot instructions
valentinpalkovic Mar 3, 2026
e23262b
Merge pull request #33994 from storybookjs/valentin/copilot-workflow-…
valentinpalkovic Mar 3, 2026
8f6f950
Write changelog for 10.3.0-alpha.14 [skip ci]
storybook-bot Mar 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ jobs:
install-code-deps: true

- name: Compile
run: yarn nx run-many --targets compile
run: yarn nx run-many --targets compile --no-cloud
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 10.2.14

- CLI: Set STORYBOOK environment variable - [#33938](https://github.com/storybookjs/storybook/pull/33938), thanks @yannbf!
- UI: Prevent crash when tag filters contain undefined entries - [#33931](https://github.com/storybookjs/storybook/pull/33931), thanks @abhaysinh1000!

## 10.2.13

- Addon Pseudo-states: Process all nested css rules - [#33605](https://github.com/storybookjs/storybook/pull/33605), thanks @hpohlmeyer!
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.prerelease.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## 10.3.0-alpha.14

- CSF-Factories: Fix ConfigFile parser false warning on `definePreview({...}).type<T>()` export default - [#33885](https://github.com/storybookjs/storybook/pull/33885), thanks @copilot-swe-agent!
- Core: Add host/origin validation to requests and websocket connections - [#33835](https://github.com/storybookjs/storybook/pull/33835), thanks @ghengeveld!
- Core: Storybook failed to load iframe.html when publishing - [#33896](https://github.com/storybookjs/storybook/pull/33896), thanks @danielalanbates!
- Core: Zoom tool refinements - Hide reset button when value is initial - [#33635](https://github.com/storybookjs/storybook/pull/33635), thanks @superLipbalm!
- Docs: Edit JSON button is now accessible at 320x256 viewport (WCAG 2.1 Reflow test) - [#33707](https://github.com/storybookjs/storybook/pull/33707), thanks @TheSeydiCharyyev!
- Manager-API: Update refs sequentially in experimental_setFilter - [#33958](https://github.com/storybookjs/storybook/pull/33958), thanks @ia319!
- UI: Allow direct kb/mouse actions on zoom tool button - [#33496](https://github.com/storybookjs/storybook/pull/33496), thanks @Sidnioulz!

## 10.3.0-alpha.13

- A11y: Add ScrollArea prop focusable for when it has static children - [#33876](https://github.com/storybookjs/storybook/pull/33876), thanks @Sidnioulz!
Expand Down
8 changes: 6 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

## Supported Versions

We release patches for fixing security vulnerabilities, primarily focusing on the latest release only.
We release patches for security vulnerabilities, primarily focusing on the latest major version.

In the event of a high-risk vulnerability, we may backport the security fixes to the minor versions of the software, starting from the latest minor version up to the latest major release. The decision to backport security fixes to older versions will be made based on a risk assessment and the feasibility of implementing the patch in those versions.
Security fixes are backported to the previous two major versions only for vulnerabilities with High or Critical CVSS scores (7.0+). The decision to backport is made based on severity assessment and the feasibility of implementing the patch in those versions.

- Latest major version: All security vulnerabilities
- Previous two major versions: High or Critical CVSS scores only
- Older versions: Not supported (Users should upgrade to a supported version)

## Reporting a Vulnerability

Expand Down
28 changes: 28 additions & 0 deletions code/addons/docs/src/blocks/controls/Object.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,31 @@ export const ReadonlyAndUndefined: Story = {
argType: { table: { readonly: true } },
},
};

export const ObjectSmallViewport: Story = {
args: {
value: {
name: 'Michael',
someDate: new Date('2022-10-30T12:31:11'),
nested: { someBool: true, someNumber: 22 },
},
},
parameters: {
chromatic: { viewports: [320] },
},
};

export const ArraySmallViewport: Story = {
args: {
value: [
'someString',
22,
true,
new Date('2022-10-30T12:31:11'),
{ someBool: true, someNumber: 22 },
],
},
parameters: {
chromatic: { viewports: [320] },
},
};
20 changes: 12 additions & 8 deletions code/addons/docs/src/blocks/controls/Object.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'

import { Button, Form, ToggleButton } from 'storybook/internal/components';

import { AddIcon, SubtractIcon } from '@storybook/icons';
import { AddIcon, EditIcon, SubtractIcon } from '@storybook/icons';

import { cloneDeep } from 'es-toolkit/object';
import { styled, useTheme } from 'storybook/theming';
Expand All @@ -18,8 +18,10 @@ const Wrapper = styled.div(({ theme }) => ({
position: 'relative',
display: 'flex',
isolation: 'isolate',
gap: 8,

'.rejt-tree': {
flex: 1,
marginLeft: '1rem',
fontSize: '13px',
listStyleType: 'none',
Expand Down Expand Up @@ -125,10 +127,9 @@ const Input = styled.input(({ theme, placeholder }) => ({
}));

const RawButton = styled(ToggleButton)({
position: 'absolute',
zIndex: 2,
top: 2,
right: 2,
alignSelf: 'flex-start',
order: 2,
marginRight: -10,
});

const RawInput = styled(Form.Textarea)(({ theme }) => ({
Expand Down Expand Up @@ -188,7 +189,7 @@ export const ObjectControl: FC<ObjectProps> = ({ name, value, onChange, argType
const onForceVisible = useCallback(() => {
onChange({});
setForceVisible(true);
}, [setForceVisible]);
}, [onChange, setForceVisible]);

const htmlElRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => {
Expand Down Expand Up @@ -240,13 +241,16 @@ export const ObjectControl: FC<ObjectProps> = ({ name, value, onChange, argType
<RawButton
disabled={readonly}
pressed={showRaw}
ariaLabel={`Edit the ${name} properties in JSON format`}
ariaLabel={`Edit ${name} as JSON`}
onClick={(e: SyntheticEvent) => {
e.preventDefault();
setShowRaw((isRaw) => !isRaw);
}}
variant="ghost"
padding="small"
size="small"
>
Edit JSON
<EditIcon />
</RawButton>
)}
{!showRaw ? (
Expand Down
21 changes: 8 additions & 13 deletions code/builders/builder-vite/src/vite-server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { logger } from 'storybook/internal/node-logger';
import type { Options } from 'storybook/internal/types';

import type { Server } from 'http';
import { dedent } from 'ts-dedent';
import type { InlineConfig, ServerOptions } from 'vite';

import { createViteLogger } from './logger';
Expand All @@ -13,9 +11,12 @@ export async function createViteServer(options: Options, devServer: Server) {

const commonCfg = await commonConfig(options, 'development');

const { allowedHosts } = await presets.apply('core', {});

const config: InlineConfig & { server: ServerOptions } = {
...commonCfg,
server: {
allowedHosts,
middlewareMode: true,
hmr: {
port: options.port,
Expand All @@ -28,18 +29,12 @@ export async function createViteServer(options: Options, devServer: Server) {
appType: 'custom' as const,
};

// '0.0.0.0' binds to all interfaces, which is useful for Docker and other containerized environments.
// but without server.allowedHosts set, requests from outside the container will be rejected.
if (options.host === '0.0.0.0' && !config.server.allowedHosts) {
// '0.0.0.0' binds to all interfaces, which is useful for Docker and other containerized environments
if (
options.host === '0.0.0.0' &&
(!allowedHosts || (Array.isArray(allowedHosts) && allowedHosts.length === 0))
) {
config.server.allowedHosts = true;
logger.warn(dedent`'host' is set to '0.0.0.0' but 'allowedHosts' is not defined.
Defaulting 'allowedHosts' to true, which permits all hostnames.
To restrict allowed hostnames, add the following to your 'viteFinal' config:
Example: { server: { allowedHosts: ['mydomain.com'] } }
See:
- https://vite.dev/config/server-options.html#server-allowedhosts
- https://storybook.js.org/docs/api/main-config/main-config-vite-final
`);
}

const finalConfig = await presets.apply('viteFinal', config, options);
Expand Down
1 change: 1 addition & 0 deletions code/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@
"get-npm-tarball-url": "^2.1.0",
"glob": "^10.5.0",
"globby": "^14.1.0",
"host-validation-middleware": "^0.1.2",
"jiti": "^2.6.1",
"js-yaml": "^4.1.0",
"jsdoc-type-pratt-parser": "^4.0.0",
Expand Down
55 changes: 47 additions & 8 deletions code/core/src/core-server/build-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { join, relative, resolve } from 'pathe';
import invariant from 'tiny-invariant';
import { dedent } from 'ts-dedent';

import Channel from '../channels';
import { detectPnp } from '../cli/detect';
import { resolvePackageDir } from '../shared/utils/module';
import { storybookDevServer } from './dev-server';
Expand All @@ -32,7 +33,7 @@ import { getManagerBuilder, getPreviewBuilder } from './utils/get-builders';
import { getServerChannel } from './utils/get-server-channel';
import { outputStartupInformation } from './utils/output-startup-information';
import { outputStats } from './utils/output-stats';
import { getServerChannelUrl, getServerPort } from './utils/server-address';
import { getServerAddresses, getServerChannelUrl, getServerPort } from './utils/server-address';
import { getServer } from './utils/server-init';
import { stripCommentsAndStrings } from './utils/strip-comments-and-strings';
import { updateCheck } from './utils/update-check';
Expand Down Expand Up @@ -91,13 +92,23 @@ export async function buildDevStandalone(
outputDir = cacheOutputDir;
}

invariant(port, 'expected options to have a port');
const { address: localAddress, networkAddress } = getServerAddresses(
port,
options.host,
options.https ? 'https' : 'http',
options.initialPath
);

options.port = port;
options.versionCheck = versionCheck;
options.configType = 'DEVELOPMENT';
options.configDir = configDir;
options.cacheKey = cacheKey;
options.outputDir = outputDir;
options.serverChannelUrl = getServerChannelUrl(port, options);
options.localAddress = localAddress;
options.networkAddress = networkAddress;

// TODO: Remove in SB11
options.pnp = await detectPnp();
Expand All @@ -111,7 +122,7 @@ export async function buildDevStandalone(
}

const config = await loadMainConfig(options);
const { framework } = config;
const { core, framework } = config;
const corePresets = [];

let frameworkName = typeof framework === 'string' ? framework : framework?.name;
Expand Down Expand Up @@ -146,7 +157,6 @@ export async function buildDevStandalone(
} catch (e) {}

const server = await getServer(options);
const channel = getServerChannel(server, getWsToken());

// Load first pass: We need to determine the builder
// We need to do this because builders might introduce 'overridePresets' which we need to take into account
Expand All @@ -158,10 +168,30 @@ export async function buildDevStandalone(
],
...options,
isCritical: true,
channel,
channel: new Channel({
transports: [
{
setHandler: () => () => console.error('CHANNEL IS NOT READY YET'),
send: () => () => console.error('CHANNEL IS NOT READY YET'),
},
],
}),
});

const { renderer, builder, disableTelemetry } = await presets.apply('core', {});
const { allowedHosts, renderer, builder, disableTelemetry } = await presets.apply('core', {});

// '0.0.0.0' binds to all interfaces, which is useful for Docker and other containerized environments.
// By default we allow requests from all hosts in this case, but the user should be made aware of the risk.
if (
options.host === '0.0.0.0' &&
(!allowedHosts || (allowedHosts !== true && allowedHosts.length === 0))
) {
logger.warn(dedent`
--host is set to 0.0.0.0 but no allowedHosts are defined. Allowing all hosts.
To restrict allowed hosts, set core.allowedHosts in your main Storybook config.
See: https://storybook.js.org/docs/api/main-config/main-config-core
`);
}

if (!builder) {
throw new MissingBuilderError();
Expand Down Expand Up @@ -202,6 +232,14 @@ export async function buildDevStandalone(

const resolvedRenderer = renderer && resolveAddonName(options.configDir, renderer, options);

const channel = getServerChannel(server, {
token: getWsToken(),
host: options.host,
allowedHosts,
localAddress,
networkAddress,
});

// Load second pass: all presets are applied in order
presets = await loadAllPresets({
corePresets: [
Expand Down Expand Up @@ -230,7 +268,7 @@ export async function buildDevStandalone(
channel,
};

const { address, networkAddress, managerResult, previewResult } = await buildOrThrow(async () =>
const { managerResult, previewResult } = await buildOrThrow(async () =>
storybookDevServer(fullOptions, server)
);

Expand Down Expand Up @@ -280,12 +318,13 @@ export async function buildDevStandalone(
updateInfo: versionCheck,
version: storybookVersion,
name,
address,
address: localAddress,
networkAddress,
allowedHosts,
managerTotalTime,
previewTotalTime,
});
}
}
return { port, address, networkAddress };
return { port, address: localAddress, networkAddress };
}
Loading
Loading