diff --git a/.eslintignore b/.eslintignore
index a9bfa7b1ede..ee0245f39b0 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -7,4 +7,4 @@ node_modules
packages/*/*/dist
packages/react-aria/dist
packages/react-stately/dist
-packages/dev/storybook-builder-preview/preview.js
+packages/dev/storybook-builder-parcel/preview.js
diff --git a/.storybook/custom-addons/strictmode/index.js b/.storybook/custom-addons/strictmode/index.js
new file mode 100644
index 00000000000..49415f62acf
--- /dev/null
+++ b/.storybook/custom-addons/strictmode/index.js
@@ -0,0 +1,37 @@
+import {addons, makeDecorator} from '@storybook/addons';
+import {getQueryParams} from '@storybook/client-api';
+import React, {StrictMode, useEffect, useState} from 'react';
+
+function StrictModeDecorator(props) {
+ let {children} = props;
+ let [isStrict, setStrict] = useState(getQueryParams()?.strict === 'true' || false);
+
+ useEffect(() => {
+ let channel = addons.getChannel();
+ let updateStrict = (val) => {
+ setStrict(val);
+ };
+ channel.on('strict/updated', updateStrict);
+ return () => {
+ channel.removeListener('strict/updated', updateStrict);
+ };
+ }, []);
+
+ return isStrict ? (
+
+ {children}
+
+ ) : children;
+}
+
+export const withStrictModeSwitcher = makeDecorator({
+ name: 'withStrictModeSwitcher',
+ parameterName: 'strictModeSwitcher',
+ wrapper: (getStory, context) => {
+ return (
+
+ {getStory(context)}
+
+ );
+ }
+});
diff --git a/.storybook/custom-addons/strictmode/register.js b/.storybook/custom-addons/strictmode/register.js
new file mode 100644
index 00000000000..b226fe1e0b3
--- /dev/null
+++ b/.storybook/custom-addons/strictmode/register.js
@@ -0,0 +1,40 @@
+import {addons, types} from '@storybook/addons';
+import {getQueryParams} from '@storybook/client-api';
+import React, {useEffect, useState} from 'react';
+
+const StrictModeToolBar = ({api}) => {
+ let channel = addons.getChannel();
+ let [isStrict, setStrict] = useState(getQueryParams()?.strict === 'true' || false);
+ let onChange = () => {
+ setStrict((old) => {
+ channel.emit('strict/updated', !old);
+ return !old;
+ })
+ };
+
+ useEffect(() => {
+ api.setQueryParams({
+ 'strict': isStrict
+ });
+ });
+
+ return (
+
+ );
+};
+
+addons.register('StrictModeSwitcher', (api) => {
+ addons.add('StrictModeSwitcher', {
+ title: 'Strict mode switcher',
+ type: types.TOOL,
+ //👇 Shows the Toolbar UI element if either the Canvas or Docs tab is active
+ match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)),
+ render: () =>
+ });
+});
diff --git a/.storybook/main.js b/.storybook/main.js
index 24a0f04b09d..5d73778c058 100644
--- a/.storybook/main.js
+++ b/.storybook/main.js
@@ -11,13 +11,11 @@ module.exports = {
'storybook-dark-mode',
'./custom-addons/provider/register',
'./custom-addons/descriptions/register',
- './custom-addons/theme/register'
+ './custom-addons/theme/register',
+ './custom-addons/strictmode/register'
],
typescript: {
check: false,
reactDocgen: false
- },
- reactOptions: {
- strictMode: process.env.STRICT_MODE
- },
+ }
};
diff --git a/.storybook/preview.js b/.storybook/preview.js
index 0b268d77a1b..bc696a5a6b5 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.js
@@ -2,6 +2,7 @@ import {configureActions} from '@storybook/addon-actions';
import React from 'react';
import {VerticalCenter} from './layout';
import {withProviderSwitcher} from './custom-addons/provider';
+import {withStrictModeSwitcher} from './custom-addons/strictmode';
// decorator order matters, the last one will be the outer most
@@ -29,5 +30,6 @@ export const decorators = [
),
+ withStrictModeSwitcher,
withProviderSwitcher
];
diff --git a/package.json b/package.json
index 049bc351fb4..5679a401113 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,6 @@
"install-16": "yarn add -W react@^16.8.0 react-dom@^16.8.0 @testing-library/react@^12 @testing-library/react-hooks@^8",
"install-17": "yarn add -W react@^17 react-dom@^17 @testing-library/react@^12 @testing-library/react-hooks@^8",
"start": "cross-env NODE_ENV=storybook start-storybook -p 9003 --ci -c '.storybook'",
- "start-strict": "cross-env NODE_ENV=storybook STRICT_MODE=1 start-storybook -p 9003 --ci -c '.storybook'",
"build:storybook": "build-storybook -c .storybook -o dist/$(git rev-parse HEAD)/storybook",
"build:storybook-16": "build-storybook -c .storybook -o dist/$(git rev-parse HEAD)/storybook-16",
"build:storybook-17": "build-storybook -c .storybook -o dist/$(git rev-parse HEAD)/storybook-17",
diff --git a/packages/@react-spectrum/provider/src/Provider.tsx b/packages/@react-spectrum/provider/src/Provider.tsx
index ac1a29401a0..7243ae74f5c 100644
--- a/packages/@react-spectrum/provider/src/Provider.tsx
+++ b/packages/@react-spectrum/provider/src/Provider.tsx
@@ -18,6 +18,7 @@ import {
useStyleProps
} from '@react-spectrum/utils';
import clsx from 'clsx';
+import {Context} from './context';
import {DOMRef} from '@react-types/shared';
import {filterDOMProps} from '@react-aria/utils';
import {I18nProvider, useLocale} from '@react-aria/i18n';
@@ -30,9 +31,6 @@ import {useColorScheme, useScale} from './mediaQueries';
// @ts-ignore
import {version} from '../package.json';
-const Context = React.createContext(null);
-Context.displayName = 'ProviderContext';
-
const DEFAULT_BREAKPOINTS = {S: 640, M: 768, L: 1024, XL: 1280, XXL: 1536};
function Provider(props: ProviderProps, ref: DOMRef) {
diff --git a/packages/@react-spectrum/provider/src/context.ts b/packages/@react-spectrum/provider/src/context.ts
new file mode 100644
index 00000000000..2c104719b04
--- /dev/null
+++ b/packages/@react-spectrum/provider/src/context.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2020 Adobe. All rights reserved.
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License. You may obtain a copy
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
+ * OF ANY KIND, either express or implied. See the License for the specific language
+ * governing permissions and limitations under the License.
+ */
+
+import {ProviderContext} from '@react-types/provider';
+import React from 'react';
+
+// Context is placed in a separate file to avoid fast refresh issue where the old provider context values
+// are immediately replaced with the null default. Stopgap solution until we fix this in parcel.
+export const Context = React.createContext(null);
+Context.displayName = 'ProviderContext';
diff --git a/yarn.lock b/yarn.lock
index 4dfcd8d0f4d..4f05e65c303 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1132,6 +1132,13 @@
dependencies:
regenerator-runtime "^0.13.11"
+"@babel/runtime@^7.6.2":
+ version "7.20.7"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd"
+ integrity sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==
+ dependencies:
+ regenerator-runtime "^0.13.11"
+
"@babel/template@^7.10.4", "@babel/template@^7.12.13", "@babel/template@^7.12.7", "@babel/template@^7.16.7", "@babel/template@^7.3.3":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155"