Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 8 additions & 2 deletions .chromatic-fc/main.js → .chromatic-fc/main.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

module.exports = {
export default {
framework: {
name: "storybook-react-parcel",
name: 'storybook-react-parcel',
options: {},
},
stories: [
Expand All @@ -15,5 +15,11 @@ module.exports = {
typescript: {
check: false,
reactDocgen: false
},
core: {
disableWhatsNewNotifications: true
},
features: {
sidebarOnboardingChecklist: false
}
};
10 changes: 8 additions & 2 deletions .chromatic/main.js → .chromatic/main.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

module.exports = {
export default {
framework: {
name: "storybook-react-parcel",
name: 'storybook-react-parcel',
options: {},
},
stories: [
Expand All @@ -15,5 +15,11 @@ module.exports = {
typescript: {
check: false,
reactDocgen: false
},
core: {
disableWhatsNewNotifications: true
},
features: {
sidebarOnboardingChecklist: false
}
};
17 changes: 17 additions & 0 deletions .storybook-s2/custom-addons/provider/preset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import path from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = path.dirname(fileURLToPath(import.meta.url));

/**
* Preset that registers our manager entry (register.tsx) with Storybook.
* The manager builder will bundle register.tsx and transpile JSX there;
* this file stays JS-free so Node can load it as a preset.
* In plain english, this is needed so that register can be a tsx file.
* @see https://github.com/storybookjs/addon-kit
* @see https://storybook.js.org/docs/addons/writing-presets#managerentries
*/
export const managerEntries = (existing: string[] = []) => [
...existing,
path.join(__dirname, "register.tsx"),
];
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import {locales} from '../../constants';
import React, {useEffect, useState} from 'react';

function ProviderFieldSetter({api}) {
let localeParam = api.getQueryParam('providerSwitcher-locale') || undefined;
let [values, setValues] = useState({locale: localeParam});
let [values, setValues] = useState(() => ({
locale: api.getQueryParam('providerSwitcher-locale') || undefined,
}));
let channel = addons.getChannel();
let onLocaleChange = (e) => {
let newValue = e.target.value || undefined;
Expand All @@ -23,19 +24,19 @@ function ProviderFieldSetter({api}) {
return () => {
channel.removeListener('rsp/ready-for-update', storySwapped);
};
});
}, [values, channel]);

useEffect(() => {
api.setQueryParams({
'providerSwitcher-locale': values.locale || ''
});
});
}, [api, values.locale]);

return (
<div style={{display: 'flex', alignItems: 'center', fontSize: '12px'}}>
<div style={{marginRight: '10px'}}>
<label htmlFor="locale">Locale: </label>
<select id="locale" name="locale" onChange={onLocaleChange} value={values.locale}>
<select id="locale" name="locale" onChange={onLocaleChange} value={values.locale || ''}>
{locales.map(locale => <option key={locale.label} value={locale.value}>{locale.label}</option>)}
</select>
</div>
Expand Down
8 changes: 7 additions & 1 deletion .storybook-s2/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { StorybookConfig } from "storybook/internal/types";
import { fileURLToPath } from "node:url";

// const excludedProps = new Set([
// 'id',
Expand All @@ -14,13 +15,15 @@ import type { StorybookConfig } from "storybook/internal/types";
// 'onInput'
// ]);

const localAddon = (rel: string) => fileURLToPath(import.meta.resolve(rel));

const config: StorybookConfig = {
stories: [
'./docs/*.mdx',
"../packages/@react-spectrum/s2/stories/*.stories.@(js|jsx|mjs|ts|tsx)",
],
addons: [
'./custom-addons/provider/register',
localAddon('./custom-addons/provider/preset.ts'),
// "@storybook/addon-styling-webpack",
"@storybook/addon-docs",
"@vueless/storybook-dark-mode",
Expand All @@ -32,6 +35,9 @@ const config: StorybookConfig = {
},
core: {
disableWhatsNewNotifications: true
},
features: {
sidebarOnboardingChecklist: false
}
// typescript: {
// reactDocgen: 'react-docgen-typescript',
Expand Down
33 changes: 22 additions & 11 deletions .storybook-s2/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import '@react-spectrum/s2/page.css';
import { themes } from 'storybook/theming';
import { DARK_MODE_EVENT_NAME } from '@vueless/storybook-dark-mode';
import { store } from '@vueless/storybook-dark-mode/dist/esm/Tool';
import { DARK_MODE_EVENT_NAME, useDarkMode } from '@vueless/storybook-dark-mode';
import { addons } from 'storybook/preview-api';
import React, { useEffect, useState } from 'react';
import React from 'react';
import {withProviderSwitcher} from './custom-addons/provider';
import {DocsContainer, Controls, Description, Primary, Stories, Subtitle, Title} from '@storybook/addon-docs/blocks';
import './global.css';

const DARK_MODE_STORAGE_KEY = 'sb-addon-themes-3';

function getInitialColorScheme(): 'dark' | 'light' {
if (typeof window === 'undefined') return 'light';
try {
const stored = window.localStorage.getItem(DARK_MODE_STORAGE_KEY);
if (stored) {
const { current } = JSON.parse(stored);
return current === 'dark' ? 'dark' : 'light';
}
} catch {}
return 'light';
}

const channel = addons.getChannel();
document.documentElement.dataset.colorScheme = store().current === 'dark' ? 'dark' : 'light';
channel.on(DARK_MODE_EVENT_NAME, isDark => document.documentElement.dataset.colorScheme = isDark ? 'dark' : 'light');
document.documentElement.dataset.colorScheme = getInitialColorScheme();
channel.on(DARK_MODE_EVENT_NAME, (isDark: boolean) => {
document.documentElement.dataset.colorScheme = isDark ? 'dark' : 'light';
});

/** @type { import('@storybook/react').Preview } */
const preview = {
Expand All @@ -21,12 +36,8 @@ const preview = {
},
docs: {
container: (props) => {
let [dark, setDark] = useState(store().current === 'dark');
useEffect(() => {
channel.on(DARK_MODE_EVENT_NAME, setDark);
return () => channel.removeListener(DARK_MODE_EVENT_NAME, setDark);
}, []);
var style = getComputedStyle(document.body)
const dark = useDarkMode();
var style = getComputedStyle(document.body);
return <DocsContainer {...props} theme={{...(dark ? themes.dark : themes.light), appContentBg: style.getPropertyValue('--s2-container-bg').trim()}} />;
},
codePanel: true,
Expand Down
6 changes: 5 additions & 1 deletion .storybook/custom-addons/provider/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {useEffect, useState} from 'react';
import {addons} from 'storybook/preview-api';
import {makeDecorator} from 'storybook/preview-api';
import {useDarkMode} from '@vueless/storybook-dark-mode';
import {Provider} from '@react-spectrum/provider';
import {expressThemes, themes, defaultTheme} from '../../constants';

Expand All @@ -17,10 +18,13 @@ function ProviderUpdater(props) {
let expressParam = params.get("providerSwitcher-express") || undefined;
let [expressValue, setExpress] = useState(expressParam === 'true');
let [storyReady, setStoryReady] = useState(window.parent === window || window.parent !== window.top); // reduce content flash because it takes a moment to get the provider details
let isDark = useDarkMode();
// Typically themes are provided with both light + dark, and both scales.
// To build our selector to see all themes, we need to hack it a bit.
let theme = (expressValue ? expressThemes : themes)[themeValue || 'light'] || defaultTheme;
let colorScheme = themeValue && themeValue.replace(/est$/, '');
// When the providerSwitcher theme is set explicitly use it, otherwise follow
// the storybook-dark-mode toolbar toggle.
let colorScheme = themeValue ? themeValue.replace(/est$/, '') : (isDark ? 'dark' : 'light');
useEffect(() => {
let channel = addons.getChannel();
let providerUpdate = (event) => {
Expand Down
19 changes: 13 additions & 6 deletions .storybook/main.js → .storybook/main.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { fileURLToPath } from "node:url";

module.exports = {
const localAddon = (rel) => fileURLToPath(import.meta.resolve(rel));

export default {
stories: [
'../packages/@{react-aria,react-stately,spectrum-icons}/*/stories/*.stories.{js,jsx,ts,tsx}',
'../packages/@react-spectrum/!(s2)/stories/*.stories.{js,jsx,ts,tsx}',
Expand All @@ -13,11 +16,11 @@ module.exports = {
'storybook/actions',
'@storybook/addon-a11y',
'@vueless/storybook-dark-mode',
'./custom-addons/provider/register.js',
'./custom-addons/descriptions/register.js',
'./custom-addons/theme/register.js',
'./custom-addons/strictmode/register.js',
'./custom-addons/scrolling/register.js'
localAddon('./custom-addons/provider'),
localAddon('./custom-addons/descriptions'),
localAddon('./custom-addons/theme'),
localAddon('./custom-addons/strictmode'),
localAddon('./custom-addons/scrolling'),
],

typescript: {
Expand All @@ -32,5 +35,9 @@ module.exports = {

core: {
disableWhatsNewNotifications: true
},

features: {
sidebarOnboardingChecklist: false
}
};
25 changes: 25 additions & 0 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {addons} from 'storybook/preview-api';
import {configureActions} from 'storybook/actions';
import {DARK_MODE_EVENT_NAME} from '@vueless/storybook-dark-mode';
import React from 'react';
import {withProviderSwitcher} from './custom-addons/provider';
import {withScrollingSwitcher} from './custom-addons/scrolling';
Expand All @@ -10,6 +12,29 @@ configureActions({
depth: 2,
});

// Reflect storybook-dark-mode state on the document root so global CSS / consumers
// can react. Mirrors the .storybook-s2 setup. Initial value comes from the addon's
// localStorage key so the very first paint is correct.
const DARK_MODE_STORAGE_KEY = 'sb-addon-themes-3';
function getInitialColorScheme() {
if (typeof window === 'undefined') return 'light';
try {
const stored = window.localStorage.getItem(DARK_MODE_STORAGE_KEY);
if (stored) {
const {current} = JSON.parse(stored);
return current === 'dark' ? 'dark' : 'light';
}
} catch (e) {}
return 'light';
}

if (typeof document !== 'undefined') {
document.documentElement.dataset.colorScheme = getInitialColorScheme();
addons.getChannel().on(DARK_MODE_EVENT_NAME, (isDark) => {
document.documentElement.dataset.colorScheme = isDark ? 'dark' : 'light';
});
}

export const parameters = {
options: {
storySort: (a, b) => {
Expand Down
11 changes: 7 additions & 4 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,13 @@ module.exports = {
]
},

// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
// "/node_modules/"
// ],
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation.
// Storybook 10 ships pure ESM in `storybook` and `@storybook/*`, so we need to let
// @swc/jest transform them instead of the default behavior of skipping all node_modules.
transformIgnorePatterns: [
'/node_modules/(?!(?:storybook|@storybook)/)',
'\\.pnp\\.[^\\/]+$'
],

// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
Expand Down
7 changes: 7 additions & 0 deletions jest.ssr.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,11 @@ module.exports = {
}
]
},

// Storybook 10 ships pure ESM in `storybook` and `@storybook/*`, so we need
// to let @swc/jest transform them instead of skipping all of node_modules.
transformIgnorePatterns: [
'/node_modules/(?!(?:storybook|@storybook)/)',
'\\.pnp\\.[^\\/]+$'
]
};
15 changes: 7 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,11 @@
"@react-spectrum/s2-icon-builder": "workspace:^",
"@spectrum-css/component-builder": "workspace:^",
"@spectrum-css/vars": "^2.3.0",
"@storybook/addon-a11y": "^9.0.18",
"@storybook/addon-docs": "^9.0.18",
"@storybook/addon-jest": "^9.0.18",
"@storybook/addon-themes": "^9.0.18",
"@storybook/react": "^9.0.18",
"@storybook/test-runner": "^0.22.0",
"@storybook/addon-a11y": "^10.0.0",
"@storybook/addon-docs": "^10.0.0",
"@storybook/addon-themes": "^10.0.0",
"@storybook/react": "^10.0.0",
"@storybook/test-runner": "^0.24.0",
"@stylistic/eslint-plugin-ts": "^2.9.0",
"@swc/core": "^1.3.36",
"@swc/jest": "^0.2.36",
Expand All @@ -139,7 +138,7 @@
"@vitejs/plugin-react": "^5.1.4",
"@vitest/browser-playwright": "^4.0.17",
"@vitest/browser-preview": "^4.0.17",
"@vueless/storybook-dark-mode": "^9.0.6",
"@vueless/storybook-dark-mode": "^10.0.0",
"@yarnpkg/types": "^4.0.0",
"autoprefixer": "^9.6.0",
"axe-playwright": "^1.1.11",
Expand Down Expand Up @@ -199,7 +198,7 @@
"rimraf": "^6.0.1",
"shadow-dom-testing-library": "^1.13.1",
"sharp": "^0.33.5",
"storybook": "^9.0.18",
"storybook": "^10.0.0",
"storybook-react-parcel": "workspace:^",
"tailwind-variants": "patch:tailwind-variants@npm%3A0.3.1#~/.yarn/patches/tailwind-variants-npm-0.3.1-48888516de.patch",
"tailwindcss": "^4.0.0",
Expand Down
8 changes: 8 additions & 0 deletions packages/dev/parcel-resolver-storybook/StorybookResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,19 @@ const reactVersion = require("react-dom/package.json").version;
import { default as NodeResolver } from "@parcel/node-resolver-core";
// @ts-ignore
import { isGlob, glob, normalizeSeparators, relativePath } from '@parcel/utils';
import { globalsNameReferenceMap } from 'storybook/internal/preview/globals';

const REACT_MAJOR_VERSION = parseInt(reactVersion.split('.')[0], 10);

module.exports = new Resolver({
async resolve({ dependency, options, specifier, pipeline, logger }) {
if (specifier in globalsNameReferenceMap) {
return {
filePath: __dirname + "/globals.js",
code: `module.exports = ${globalsNameReferenceMap[specifier]};`
};
}

// Workaround for interop issue
if (specifier === "react-dom/client" && REACT_MAJOR_VERSION < 18) {
return {
Expand Down
2 changes: 1 addition & 1 deletion packages/dev/parcel-transformer-storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@parcel/plugin": "^2.16.3",
"@parcel/source-map": "^2.1.1",
"react-docgen-typescript": "^2.2.2",
"storybook": "^9.0.18",
"storybook": "^10.0.0",
"typescript": "^5.5.0"
},
"scripts": {
Expand Down
Loading
Loading