diff --git a/addons/background/src/BackgroundPanel.js b/addons/background/src/BackgroundPanel.js index bf1172ba9230..f03671fcbb63 100644 --- a/addons/background/src/BackgroundPanel.js +++ b/addons/background/src/BackgroundPanel.js @@ -63,7 +63,7 @@ export default class BackgroundPanel extends Component { constructor(props) { super(props); - const { channel, api } = props; + const { channel } = props; // A channel is explicitly passed in for testing if (channel) { @@ -73,6 +73,20 @@ export default class BackgroundPanel extends Component { } this.state = { backgrounds: [] }; + } + + componentDidMount() { + this.iframe = document.getElementById(storybookIframe); + + if (!this.iframe) { + throw new Error('Cannot find Storybook iframe'); + } + + Object.keys(style.iframe).forEach(prop => { + this.iframe.style[prop] = style.iframe[prop]; + }); + + const { api } = this.props; this.channel.on('background-set', backgrounds => { this.setState({ backgrounds }); @@ -93,18 +107,6 @@ export default class BackgroundPanel extends Component { }); } - componentDidMount() { - this.iframe = document.getElementById(storybookIframe); - - if (!this.iframe) { - throw new Error('Cannot find Storybook iframe'); - } - - Object.keys(style.iframe).forEach(prop => { - this.iframe.style[prop] = style.iframe[prop]; - }); - } - setBackgroundFromSwatch = background => { this.updateIframe(background); this.props.api.setQueryParams({ background }); diff --git a/addons/background/src/index.js b/addons/background/src/index.js index d74e08d6da5c..d4b65008310e 100644 --- a/addons/background/src/index.js +++ b/addons/background/src/index.js @@ -7,7 +7,7 @@ export class BackgroundDecorator extends React.Component { constructor(props) { super(props); - const { channel, story } = props; + const { channel } = props; // A channel is explicitly passed in for testing if (channel) { @@ -15,26 +15,18 @@ export class BackgroundDecorator extends React.Component { } else { this.channel = addons.getChannel(); } - - this.story = story(); } - componentWillMount() { + componentDidMount() { this.channel.emit('background-set', this.props.backgrounds); } - componentWillReceiveProps(nextProps) { - if (nextProps.story !== this.props.story) { - this.story = nextProps.story(); - } - } - componentWillUnmount() { this.channel.emit('background-unset'); } render() { - return this.story; + return this.props.story(); } } BackgroundDecorator.propTypes = { diff --git a/addons/centered/package.json b/addons/centered/package.json index 560382700aac..305c427bc71a 100644 --- a/addons/centered/package.json +++ b/addons/centered/package.json @@ -14,7 +14,7 @@ "global": "^4.3.2" }, "devDependencies": { - "react-dom": "^16.2.0" + "react-dom": "^16.3.0" }, "peerDependencies": { "react": "*" diff --git a/addons/info/package.json b/addons/info/package.json index f75261451dbb..11b67b8d06f8 100644 --- a/addons/info/package.json +++ b/addons/info/package.json @@ -30,7 +30,7 @@ "devDependencies": { "@storybook/addon-actions": "4.0.0-alpha.1", "@storybook/react": "4.0.0-alpha.1", - "react-test-renderer": "^16.1.0" + "react-test-renderer": "^16.3.0" }, "peerDependencies": { "react": "*", diff --git a/addons/knobs/src/components/Panel.js b/addons/knobs/src/components/Panel.js index dcfd959d1210..3763cef2d964 100644 --- a/addons/knobs/src/components/Panel.js +++ b/addons/knobs/src/components/Panel.js @@ -60,6 +60,9 @@ export default class Panel extends React.Component { this.lastEdit = getTimestamp(); this.loadedFromUrl = false; + } + + componentDidMount() { this.props.channel.on('addon:knobs:setKnobs', this.setKnobs); this.props.channel.on('addon:knobs:setOptions', this.setOptions); diff --git a/addons/links/package.json b/addons/links/package.json index 6a837f4811ba..e0259c32c784 100644 --- a/addons/links/package.json +++ b/addons/links/package.json @@ -30,8 +30,8 @@ "devDependencies": { "@storybook/react": "4.0.0-alpha.1", "enzyme": "^3.3.0", - "react": "^16.1.0", - "react-dom": "^16.1.0" + "react": "^16.3.0", + "react-dom": "^16.3.0" }, "peerDependencies": { "@storybook/addons": "^3.3.0", diff --git a/addons/storyshots/package.json b/addons/storyshots/package.json index 3fa5df8054c1..4a6a9c04006f 100644 --- a/addons/storyshots/package.json +++ b/addons/storyshots/package.json @@ -32,8 +32,8 @@ "@storybook/addons": "4.0.0-alpha.1", "@storybook/react": "4.0.0-alpha.1", "enzyme-to-json": "^3.3.3", - "react": "^16.1.0", - "react-dom": "^16.1.0" + "react": "^16.3.0", + "react-dom": "^16.3.0" }, "peerDependencies": { "@storybook/addons": "4.0.0-alpha.1", diff --git a/addons/storysource/src/StoryPanel.js b/addons/storysource/src/StoryPanel.js index 815e0390a931..eb4afd34ba2b 100644 --- a/addons/storysource/src/StoryPanel.js +++ b/addons/storysource/src/StoryPanel.js @@ -46,7 +46,13 @@ export default class StoryPanel extends Component { this.state = { source: '// Here will be dragons 🐉' }; - const { channel } = props; + this.setSelectedStoryRef = this.setSelectedStoryRef.bind(this); + this.lineRenderer = this.lineRenderer.bind(this); + this.clickOnStory = this.clickOnStory.bind(this); + } + + componentDidMount() { + const { channel } = this.props; channel.on(EVENT_ID, ({ source, currentLocation, locationsMap }) => { const locationsKeys = StoryPanel.getLocationKeys(locationsMap); @@ -58,10 +64,6 @@ export default class StoryPanel extends Component { locationsKeys, }); }); - - this.setSelectedStoryRef = this.setSelectedStoryRef.bind(this); - this.lineRenderer = this.lineRenderer.bind(this); - this.clickOnStory = this.clickOnStory.bind(this); } componentDidUpdate() { diff --git a/app/mithril/package.json b/app/mithril/package.json index 74db4c70857c..282a80b655ca 100644 --- a/app/mithril/package.json +++ b/app/mithril/package.json @@ -49,8 +49,8 @@ "html-webpack-plugin": "^3.1.0", "json5": "^0.5.1", "markdown-loader": "^2.0.2", - "react": "^16.2.0", - "react-dom": "^16.2.0", + "react": "^16.3.0", + "react-dom": "^16.3.0", "util-deprecate": "^1.0.2", "webpack": "^4.4.1", "webpack-hot-middleware": "^2.21.2" diff --git a/app/polymer/package.json b/app/polymer/package.json index c83b94251af0..3a0cb2f63a7e 100644 --- a/app/polymer/package.json +++ b/app/polymer/package.json @@ -49,8 +49,8 @@ "global": "^4.3.2", "html-webpack-plugin": "^3.1.0", "json5": "^0.5.1", - "react": "^16.0.0", - "react-dom": "^16.0.0", + "react": "^16.3.0", + "react-dom": "^16.3.0", "util-deprecate": "^1.0.2", "webpack": "^4.4.1", "webpack-hot-middleware": "^2.21.2" diff --git a/app/react-native/package.json b/app/react-native/package.json index a4bbf39306b7..3852253bec5d 100644 --- a/app/react-native/package.json +++ b/app/react-native/package.json @@ -48,6 +48,7 @@ "babel-runtime": "^6.26.0", "case-sensitive-paths-webpack-plugin": "^2.1.2", "commander": "^2.15.1", + "dotenv-webpack": "^1.5.5", "express": "^4.16.3", "find-cache-dir": "^1.0.0", "global": "^4.3.2", diff --git a/app/react-native/src/server/config/webpack.config.js b/app/react-native/src/server/config/webpack.config.js index 3c00319851b5..0389b5d0cd9e 100644 --- a/app/react-native/src/server/config/webpack.config.js +++ b/app/react-native/src/server/config/webpack.config.js @@ -1,5 +1,6 @@ import path from 'path'; import webpack from 'webpack'; +import Dotenv from 'dotenv-webpack'; import WatchMissingNodeModulesPlugin from '@storybook/react-dev-utils/WatchMissingNodeModulesPlugin'; import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin'; import HtmlWebpackPlugin from 'html-webpack-plugin'; @@ -27,6 +28,7 @@ const getConfig = options => ({ new webpack.HotModuleReplacementPlugin(), new CaseSensitivePathsPlugin(), new WatchMissingNodeModulesPlugin(nodeModulesPaths), + new Dotenv({ silent: true }), ], module: { rules: [ diff --git a/app/react-native/src/server/config/webpack.config.prod.js b/app/react-native/src/server/config/webpack.config.prod.js index 3235cedb9678..3048db283f5f 100644 --- a/app/react-native/src/server/config/webpack.config.prod.js +++ b/app/react-native/src/server/config/webpack.config.prod.js @@ -1,5 +1,6 @@ import path from 'path'; import webpack from 'webpack'; +import Dotenv from 'dotenv-webpack'; import HtmlWebpackPlugin from 'html-webpack-plugin'; import { includePaths, excludePaths } from './utils'; @@ -31,6 +32,7 @@ const getConfig = options => { }), new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"production"' }), new webpack.optimize.DedupePlugin(), + new Dotenv({ silent: true }), ], module: { rules: [ diff --git a/app/react/package.json b/app/react/package.json index 2679d2c92969..03800a2de7f2 100644 --- a/app/react/package.json +++ b/app/react/package.json @@ -67,7 +67,7 @@ "peerDependencies": { "babel-core": "^6.26.0 || ^7.0.0-0", "babel-runtime": ">=6.0.0", - "react": ">=15.0.0 || ^16.0.0", - "react-dom": ">=15.0.0 || ^16.0.0" + "react": ">=15.0.0", + "react-dom": ">=15.0.0" } } diff --git a/app/react/src/client/preview/render.js b/app/react/src/client/preview/render.js index c5d591e7915a..ed1d1d09af79 100644 --- a/app/react/src/client/preview/render.js +++ b/app/react/src/client/preview/render.js @@ -19,12 +19,19 @@ if (isBrowser) { rootEl = document.getElementById('root'); } +function render(node, el) { + ReactDOM.render( + process.env.STORYBOOK_EXAMPLE_APP ? {node} : node, + el + ); +} + export function renderError(error) { const properError = new Error(error.title); properError.stack = error.description; const redBox = ; - ReactDOM.render(redBox, rootEl); + render(redBox, rootEl); } export function renderException(error) { @@ -33,7 +40,7 @@ export function renderException(error) { const realError = new Error(error.message); realError.stack = error.stack; const redBox = ; - ReactDOM.render(redBox, rootEl); + render(redBox, rootEl); // Log the stack to the console. So, user could check the source code. logger.error(error.stack); @@ -49,7 +56,7 @@ export function renderMain(data, storyStore, forceRender) { const revision = storyStore.getRevision(); const story = storyStore.getStoryWithContext(selectedKind, selectedStory); if (!story) { - ReactDOM.render(noPreview, rootEl); + render(noPreview, rootEl); return null; } @@ -101,7 +108,7 @@ export function renderMain(data, storyStore, forceRender) { return renderError(error); } - ReactDOM.render(element, rootEl); + render(element, rootEl); return null; } diff --git a/app/vue/package.json b/app/vue/package.json index ae08a16479c1..6d061b5f6152 100644 --- a/app/vue/package.json +++ b/app/vue/package.json @@ -47,8 +47,8 @@ "html-webpack-plugin": "^3.1.0", "json5": "^0.5.1", "markdown-loader": "^2.0.2", - "react": "^16.2.0", - "react-dom": "^16.2.0", + "react": "^16.3.0", + "react-dom": "^16.3.0", "util-deprecate": "^1.0.2", "webpack": "^4.4.1", "webpack-hot-middleware": "^2.21.2" diff --git a/examples/angular-cli/.env b/examples/angular-cli/.env new file mode 100644 index 000000000000..d24e628d2810 --- /dev/null +++ b/examples/angular-cli/.env @@ -0,0 +1 @@ +STORYBOOK_EXAMPLE_APP=true diff --git a/examples/cra-kitchen-sink/package.json b/examples/cra-kitchen-sink/package.json index 80a0962e18bd..26c1a11e5e19 100644 --- a/examples/cra-kitchen-sink/package.json +++ b/examples/cra-kitchen-sink/package.json @@ -13,8 +13,8 @@ "dependencies": { "global": "^4.3.2", "prop-types": "^15.6.1", - "react": "^16.2.0", - "react-dom": "^16.2.0" + "react": "^16.3.0", + "react-dom": "^16.3.0" }, "devDependencies": { "@storybook/addon-a11y": "4.0.0-alpha.1", diff --git a/examples/crna-kitchen-sink/.env b/examples/crna-kitchen-sink/.env new file mode 100644 index 000000000000..d24e628d2810 --- /dev/null +++ b/examples/crna-kitchen-sink/.env @@ -0,0 +1 @@ +STORYBOOK_EXAMPLE_APP=true diff --git a/examples/mithril-kitchen-sink/.env b/examples/mithril-kitchen-sink/.env new file mode 100644 index 000000000000..d24e628d2810 --- /dev/null +++ b/examples/mithril-kitchen-sink/.env @@ -0,0 +1 @@ +STORYBOOK_EXAMPLE_APP=true diff --git a/examples/mithril-kitchen-sink/.gitignore b/examples/mithril-kitchen-sink/.gitignore index 6c96c5cff124..56b6cc8a3115 100644 --- a/examples/mithril-kitchen-sink/.gitignore +++ b/examples/mithril-kitchen-sink/.gitignore @@ -11,5 +11,4 @@ build # misc .DS_Store -.env npm-debug.log diff --git a/examples/official-storybook/.env b/examples/official-storybook/.env index 03fe9204f809..f088c261657f 100644 --- a/examples/official-storybook/.env +++ b/examples/official-storybook/.env @@ -1 +1,2 @@ DISPLAY_WARNING=none +STORYBOOK_EXAMPLE_APP=true diff --git a/examples/official-storybook/package.json b/examples/official-storybook/package.json index 071ba7c7b871..48afe6b6faf5 100644 --- a/examples/official-storybook/package.json +++ b/examples/official-storybook/package.json @@ -35,9 +35,9 @@ "global": "^4.3.2", "paths.macro": "^2.0.2", "prop-types": "^15.6.1", - "react": "^16.2.0", + "react": "^16.3.0", "react-chromatic": "^0.8.1", - "react-dom": "^16.2.0", + "react-dom": "^16.3.0", "uuid": "^3.2.1" } } diff --git a/examples/polymer-cli/.env b/examples/polymer-cli/.env new file mode 100644 index 000000000000..d24e628d2810 --- /dev/null +++ b/examples/polymer-cli/.env @@ -0,0 +1 @@ +STORYBOOK_EXAMPLE_APP=true diff --git a/examples/react-native-vanilla/.env b/examples/react-native-vanilla/.env new file mode 100644 index 000000000000..d24e628d2810 --- /dev/null +++ b/examples/react-native-vanilla/.env @@ -0,0 +1 @@ +STORYBOOK_EXAMPLE_APP=true diff --git a/lib/components/src/navigation/routed_link.js b/lib/components/src/navigation/routed_link.js index eab73e97f724..e3ba954b8a08 100644 --- a/lib/components/src/navigation/routed_link.js +++ b/lib/components/src/navigation/routed_link.js @@ -6,18 +6,18 @@ const LEFT_BUTTON = 0; const isPlainLeftClick = e => e.button === LEFT_BUTTON && !e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey; -const wrapOnClick = fn => e => (isPlainLeftClick(e) ? e.preventDefault() || fn(e) : false); - export default class RoutedLink extends React.Component { - constructor(props, ...rest) { - super(...[props, ...rest]); + constructor(...attrs) { + super(...attrs); - const { onClick } = props; - this.onClick = onClick ? wrapOnClick(onClick) : undefined; + this.onClick = this.onClick.bind(this); } - componentWillUpdate({ onClick }) { - this.onClick = wrapOnClick(onClick); + onClick(e) { + if (isPlainLeftClick(e)) { + e.preventDefault(); + this.props.onClick(e); + } } render() { diff --git a/lib/core/package.json b/lib/core/package.json index 0e8ec803754d..c0be626dde9a 100644 --- a/lib/core/package.json +++ b/lib/core/package.json @@ -37,8 +37,6 @@ "postcss-loader": "^2.1.3", "prop-types": "^15.6.1", "qs": "^6.5.1", - "react": "^16.0.0", - "react-dom": "^16.0.0", "redux": "^3.7.2", "serve-favicon": "^2.4.5", "shelljs": "^0.8.1", @@ -48,5 +46,9 @@ "webpack": "^4.4.1", "webpack-dev-middleware": "^3.1.0", "webpack-hot-middleware": "^2.21.2" + }, + "peerDependencies": { + "react": ">=15.0.0", + "react-dom": ">=15.0.0" } } diff --git a/lib/ui/package.json b/lib/ui/package.json index b5719ab9cdc0..12784390dd74 100644 --- a/lib/ui/package.json +++ b/lib/ui/package.json @@ -18,7 +18,7 @@ "@storybook/components": "4.0.0-alpha.1", "@storybook/mantra-core": "^1.7.2", "@storybook/podda": "^1.2.3", - "@storybook/react-komposer": "^2.0.3", + "@storybook/react-komposer": "^2.0.4", "babel-runtime": "^6.26.0", "deep-equal": "^1.0.1", "events": "^2.0.0", @@ -33,6 +33,7 @@ "qs": "^6.5.1", "react-fuzzy": "^0.5.2", "react-icons": "^2.2.7", + "react-lifecycles-compat": "^1.1.0", "react-modal": "^3.3.2", "react-split-pane": "^0.1.77", "react-treebeard": "^2.1.0" diff --git a/lib/ui/src/libs/withLifecycleDecorator.js b/lib/ui/src/libs/withLifecycleDecorator.js index df364c630351..9d16977cd126 100644 --- a/lib/ui/src/libs/withLifecycleDecorator.js +++ b/lib/ui/src/libs/withLifecycleDecorator.js @@ -3,12 +3,16 @@ import PropTypes from 'prop-types'; // A small utility to add before/afterEach to stories. class WithLifecyle extends Component { - componentWillMount() { - this.props.beforeEach(); + constructor(props, ...rest) { + super(props, ...rest); + + props.beforeEach(); } + componentWillUnmount() { this.props.afterEach(); } + render() { return this.props.storyFn(); } diff --git a/lib/ui/src/modules/ui/components/layout/dimensions.js b/lib/ui/src/modules/ui/components/layout/dimensions.js index 3db18d52c4da..ec9f556975d8 100644 --- a/lib/ui/src/modules/ui/components/layout/dimensions.js +++ b/lib/ui/src/modules/ui/components/layout/dimensions.js @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import polyfill from 'react-lifecycles-compat'; import { baseFonts } from '@storybook/components'; @@ -30,15 +31,19 @@ class Dimensions extends React.Component { super(props); this.state = { + ...props, isVisible: false, }; this.hideTimeout = null; } - componentWillReceiveProps({ width, height }) { - if (width !== this.state.width || height !== this.state.height) { - this.onChange(width, height); + componentDidUpdate() { + if (this.state.isVisible) { + clearTimeout(this.hideTimeout); + this.hideTimeout = setTimeout(() => { + this.setState({ isVisible: false }); + }, DISPLAY_TIMEOUT); } } @@ -46,17 +51,6 @@ class Dimensions extends React.Component { clearTimeout(this.hideTimeout); } - onChange(width, height) { - this.setState({ isVisible: true }); - - this.hideTimeout = setTimeout(() => { - // Ensure the dimensions aren't still changing - if (width === this.props.width && height === this.props.height) { - this.setState({ isVisible: false }); - } - }, DISPLAY_TIMEOUT); - } - render() { if (!this.state.isVisible) { return null; @@ -74,9 +68,18 @@ class Dimensions extends React.Component { } } +Dimensions.getDerivedStateFromProps = (nextProps, prevState) => { + if (nextProps.width !== prevState.width || nextProps.height !== prevState.height) { + return { ...nextProps, isVisible: true }; + } + return null; +}; + Dimensions.propTypes = { width: PropTypes.number.isRequired, height: PropTypes.number.isRequired, }; +polyfill(Dimensions); + export default Dimensions; diff --git a/lib/ui/src/modules/ui/components/search_box.stories.js b/lib/ui/src/modules/ui/components/search_box.stories.js index b9b6f5eece7b..a4078a99f3ae 100644 --- a/lib/ui/src/modules/ui/components/search_box.stories.js +++ b/lib/ui/src/modules/ui/components/search_box.stories.js @@ -1,4 +1,5 @@ import React from 'react'; +import ReactModal from 'react-modal'; import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { navigator } from 'global'; @@ -14,6 +15,8 @@ const stories = [ const onSelectStory = action('onSelectStory'); const onClose = action('onClose'); +ReactModal.setAppElement('#root'); + // For some reason react-modal causes an segfault (infinite loop maybe?) // when rendered by storyshots/react-test-renderer if (!navigator.userAgent.match(/Node\.js/) && !navigator.userAgent.match(/jsdom/)) { diff --git a/lib/ui/src/modules/ui/components/stories_panel/stories_tree/index.js b/lib/ui/src/modules/ui/components/stories_panel/stories_tree/index.js index 907a1db89439..06ec612ece10 100644 --- a/lib/ui/src/modules/ui/components/stories_panel/stories_tree/index.js +++ b/lib/ui/src/modules/ui/components/stories_panel/stories_tree/index.js @@ -1,6 +1,7 @@ import { Treebeard } from 'react-treebeard'; import PropTypes from 'prop-types'; import React from 'react'; +import polyfill from 'react-lifecycles-compat'; import deepEqual from 'deep-equal'; import TreeHeader from './tree_header'; import treeNodeTypes from './tree_node_type'; @@ -47,33 +48,6 @@ class Stories extends React.Component { }; } - componentWillReceiveProps(nextProps) { - const { - selectedHierarchy: nextSelectedHierarchy = [], - storyFilter: nextStoryFilter, - } = nextProps; - - const { - selectedHierarchy: currentSelectedHierarchy = [], - storyFilter: currentStoryFilter, - } = this.props; - - const shouldClearFilteredNodes = nextStoryFilter !== currentStoryFilter; - const selectedHierarchyChanged = !deepEqual(nextSelectedHierarchy, currentSelectedHierarchy); - - if (selectedHierarchyChanged || shouldClearFilteredNodes) { - const selectedNodes = getSelectedNodes(nextSelectedHierarchy); - - this.setState(prevState => ({ - overriddenFilteredNodes: shouldClearFilteredNodes ? {} : prevState.overriddenFilteredNodes, - nodes: { - ...prevState.nodes, - ...selectedNodes, - }, - })); - } - } - onToggle(node, toggled) { if (node.story) { this.fireOnKindAndStory(node.kind, node.story); @@ -173,6 +147,30 @@ class Stories extends React.Component { } } +Stories.getDerivedStateFromProps = (nextProps, prevState) => { + const { selectedHierarchy = [], storyFilter } = nextProps; + + const { prevSelectedHierarchy = [], prevStoryFilter } = prevState; + + const shouldClearFilteredNodes = storyFilter !== prevStoryFilter; + const selectedHierarchyChanged = !deepEqual(selectedHierarchy, prevSelectedHierarchy); + + if (selectedHierarchyChanged || shouldClearFilteredNodes) { + const selectedNodes = getSelectedNodes(selectedHierarchy); + + return { + overriddenFilteredNodes: shouldClearFilteredNodes ? {} : prevState.overriddenFilteredNodes, + nodes: { + ...prevState.nodes, + ...selectedNodes, + }, + prevSelectedHierarchy: selectedHierarchy, + prevStoryFilter: storyFilter, + }; + } + return null; +}; + Stories.defaultProps = { onSelectStory: null, storiesHierarchy: null, @@ -194,4 +192,6 @@ Stories.propTypes = { sidebarAnimations: PropTypes.bool, }; +polyfill(Stories); + export default Stories; diff --git a/lib/ui/src/modules/ui/components/stories_panel/text_filter.js b/lib/ui/src/modules/ui/components/stories_panel/text_filter.js index 0e88d0ffdc37..df4f214ce013 100755 --- a/lib/ui/src/modules/ui/components/stories_panel/text_filter.js +++ b/lib/ui/src/modules/ui/components/stories_panel/text_filter.js @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import polyfill from 'react-lifecycles-compat'; import debounce from 'lodash.debounce'; import { baseFonts } from '@storybook/components'; @@ -45,27 +46,17 @@ const clearButtonStyle = { const debounceFilterChangeTimeout = 500; -export default class TextFilter extends React.Component { +class TextFilter extends React.Component { constructor(props) { super(props); - this.state = { - query: props.text, - }; + this.state = {}; this.onChange = this.onChange.bind(this); this.fireOnClear = this.fireOnClear.bind(this); this.changeFilter = debounce(this.changeFilter, debounceFilterChangeTimeout); } - componentWillReceiveProps(nextProps) { - if (nextProps.text !== this.state.query) { - this.setState({ - query: nextProps.text, - }); - } - } - onChange(event) { const text = event.target.value; this.setState({ query: text }); @@ -107,6 +98,16 @@ export default class TextFilter extends React.Component { } } +TextFilter.getDerivedStateFromProps = ({ text }, { prevText }) => { + if (text !== prevText) { + return { + query: text, + prevText: text, + }; + } + return null; +}; + TextFilter.defaultProps = { text: defaultTextValue, onChange: null, @@ -114,7 +115,12 @@ TextFilter.defaultProps = { }; TextFilter.propTypes = { + // eslint-disable-next-line react/no-unused-prop-types text: PropTypes.string, onChange: PropTypes.func, onClear: PropTypes.func, }; + +polyfill(TextFilter); + +export default TextFilter; diff --git a/lib/ui/src/modules/ui/routes.js b/lib/ui/src/modules/ui/routes.js index 79929c704083..5fa050563fce 100755 --- a/lib/ui/src/modules/ui/routes.js +++ b/lib/ui/src/modules/ui/routes.js @@ -18,8 +18,10 @@ export default function(injectDeps, { clientStore, provider, domNode }) { // Tell react-modal which element to mark as aria-hidden ReactModal.setAppElement(domNode); + const Container = process.env.STORYBOOK_EXAMPLE_APP ? React.StrictMode : 'div'; + const root = ( -
+ } preview={() => } @@ -27,7 +29,7 @@ export default function(injectDeps, { clientStore, provider, domNode }) { /> -
+ ); ReactDOM.render(root, domNode); } diff --git a/package.json b/package.json index 82edbed5914c..aa5a0d8f596e 100644 --- a/package.json +++ b/package.json @@ -89,9 +89,9 @@ "polymer-webpack-loader": "^2.0.2", "prettier": "^1.11.1", "raf": "^3.4.0", - "react": "^16.2.0", - "react-dom": "^16.2.0", - "react-test-renderer": "^16.2.0", + "react": "^16.3.0", + "react-dom": "^16.3.0", + "react-test-renderer": "^16.3.0", "remark-cli": "^5.0.0", "remark-lint": "^6.0.1", "remark-preset-lint-recommended": "^3.0.1", diff --git a/yarn.lock b/yarn.lock index 03fc4a105c45..80d45cecc62c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -331,7 +331,7 @@ strip-ansi "4.0.0" text-table "0.2.0" -"@storybook/react-komposer@^2.0.1", "@storybook/react-komposer@^2.0.3": +"@storybook/react-komposer@^2.0.1": version "2.0.3" resolved "https://registry.yarnpkg.com/@storybook/react-komposer/-/react-komposer-2.0.3.tgz#f9e12a9586b2ce95c24c137eabb8b71527ddb369" dependencies: @@ -341,6 +341,16 @@ lodash.pick "^4.4.0" shallowequal "^0.2.2" +"@storybook/react-komposer@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@storybook/react-komposer/-/react-komposer-2.0.4.tgz#c2c0d4a75d9b4a9c0c6b46f14ab050f458ad4bb0" + dependencies: + "@storybook/react-stubber" "^1.0.0" + babel-runtime "^6.11.6" + hoist-non-react-statics "^1.2.0" + lodash.pick "^4.4.0" + shallowequal "^0.2.2" + "@storybook/react-simple-di@^1.2.1": version "1.3.0" resolved "https://registry.yarnpkg.com/@storybook/react-simple-di/-/react-simple-di-1.3.0.tgz#13116d89a2f42898716a7f8c4095b47415526371" @@ -13040,9 +13050,9 @@ react-docgen@^2.20.0: node-dir "^0.1.10" recast "^0.12.6" -react-dom@^16.0.0, react-dom@^16.1.0, react-dom@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" +react-dom@^16.0.0, react-dom@^16.3.0: + version "16.3.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.3.0.tgz#b318e52184188ecb5c3e81117420cca40618643e" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -13085,6 +13095,14 @@ react-inspector@^2.2.2: babel-runtime "^6.26.0" is-dom "^1.0.9" +react-is@^16.3.0: + version "16.3.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.0.tgz#f0e8bfd8c09b480dd610b8639d9ed65c13601224" + +react-lifecycles-compat@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-1.1.0.tgz#6641d0709bd5505329b5c90322147ef2d343485c" + react-modal@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.3.2.tgz#b13da9490653a7c76bc0e9600323eb1079c620e7" @@ -13250,7 +13268,7 @@ react-syntax-highlighter@^7.0.2: prismjs "^1.8.4" refractor "^2.0.0" -react-test-renderer@^16.0.0-0, react-test-renderer@^16.1.0, react-test-renderer@^16.2.0: +react-test-renderer@^16.0.0-0: version "16.2.0" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.2.0.tgz#bddf259a6b8fcd8555f012afc8eacc238872a211" dependencies: @@ -13258,6 +13276,15 @@ react-test-renderer@^16.0.0-0, react-test-renderer@^16.1.0, react-test-renderer@ object-assign "^4.1.1" prop-types "^15.6.0" +react-test-renderer@^16.3.0: + version "16.3.0" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.3.0.tgz#7e88d8cb4c2b95c161b6c6c998991166f74d473e" + dependencies: + fbjs "^0.8.16" + object-assign "^4.1.1" + prop-types "^15.6.0" + react-is "^16.3.0" + react-textarea-autosize@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-5.2.1.tgz#2b78f9067180f41b08ac59f78f1581abadd61e54" @@ -13296,9 +13323,9 @@ react-treebeard@^2.1.0: shallowequal "^0.2.2" velocity-react "^1.3.1" -react@^16.0.0, react@^16.1.0, react@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" +react@^16.0.0, react@^16.3.0: + version "16.3.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.3.0.tgz#fc5a01c68f91e9b38e92cf83f7b795ebdca8ddff" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0"