diff --git a/.eslintignore b/.eslintignore index 3675648e816b3221576be2393fd3496bb99dad70..93c033154fbdf0e4cb6ef0dd9c31570e2b6cd475 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ node_modules/* build/* +dist/* diff --git a/.gitignore b/.gitignore index 8f98cc55bfece970be899bd47c999bfd9ae70369..0b8a0db40e62622a65702b0b042181de5136286e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ npm-* # Build /build +/dist /.opt-in # generated translation files diff --git a/src/containers/language-selector.jsx b/src/containers/language-selector.jsx index ae0d2405cffb888abd2d8500a93ea382f3b53c5b..316b1577a367a4314ee7a610f72b9bee2516874d 100644 --- a/src/containers/language-selector.jsx +++ b/src/containers/language-selector.jsx @@ -1,5 +1,4 @@ import {connect} from 'react-redux'; -import {updateIntl} from '../reducers/intl.js'; import LanguageSelectorComponent from '../components/language-selector/language-selector.jsx'; @@ -7,10 +6,9 @@ const mapStateToProps = state => ({ currentLocale: state.intl.locale }); -const mapDispatchToProps = dispatch => ({ +const mapDispatchToProps = () => ({ onChange: e => { e.preventDefault(); - dispatch(updateIntl(e.target.value)); } }); diff --git a/src/lib/app-state-hoc.jsx b/src/lib/app-state-hoc.jsx index 2894cda13e372e2936868b6cd913c9f040f9bb45..158ac40d05408f2324614e409e4af2f838ff36b8 100644 --- a/src/lib/app-state-hoc.jsx +++ b/src/lib/app-state-hoc.jsx @@ -3,7 +3,9 @@ import {Provider} from 'react-redux'; import {createStore, applyMiddleware, compose} from 'redux'; import throttle from 'redux-throttle'; -import {intlInitialState, IntlProvider} from '../reducers/intl.js'; +import {intlShape} from 'react-intl'; +import {IntlProvider, updateIntl} from 'react-intl-redux'; +import {intlInitialState} from '../reducers/intl.js'; import reducer from '../reducers/gui'; const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; @@ -12,7 +14,6 @@ const enhancer = composeEnhancers( throttle(300, {leading: true, trailing: true}) ) ); -const store = createStore(reducer, intlInitialState, enhancer); import ErrorBoundary from '../containers/error-boundary.jsx'; @@ -22,15 +23,32 @@ import ErrorBoundary from '../containers/error-boundary.jsx'; * @returns {React.Component} component with redux and intl state provided */ const AppStateHOC = function (WrappedComponent) { - const AppStateWrapper = ({...props}) => ( - <Provider store={store}> - <IntlProvider> - <ErrorBoundary> - <WrappedComponent {...props} /> - </ErrorBoundary> - </IntlProvider> - </Provider> - ); + class AppStateWrapper extends React.Component { + constructor (props) { + super(props); + this.store = createStore(reducer, (props.intl || intlInitialState), enhancer); + } + componentDidUpdate (prevProps) { + if (prevProps.intl !== this.props.intl) updateIntl(this.props.intl); + } + render () { + return ( + <Provider store={this.store}> + <IntlProvider> + <ErrorBoundary> + <WrappedComponent {...this.props} /> + </ErrorBoundary> + </IntlProvider> + </Provider> + ); + + } + + + } + AppStateWrapper.propTypes = { + intl: intlShape + }; return AppStateWrapper; }; diff --git a/src/examples/blocks-only.css b/src/playground/blocks-only.css similarity index 100% rename from src/examples/blocks-only.css rename to src/playground/blocks-only.css diff --git a/src/examples/blocks-only.jsx b/src/playground/blocks-only.jsx similarity index 93% rename from src/examples/blocks-only.jsx rename to src/playground/blocks-only.jsx index 8d5159e825105374827e818ce7009e57587e87de..417ab85c9ff0143ec77b80b2eaa9810e9bd5cd9c 100644 --- a/src/examples/blocks-only.jsx +++ b/src/playground/blocks-only.jsx @@ -6,7 +6,7 @@ import AppStateHOC from '../lib/app-state-hoc.jsx'; import Controls from '../containers/controls.jsx'; import Blocks from '../containers/blocks.jsx'; import GUI from '../containers/gui.jsx'; -import ProjectLoaderHOC from '../lib/project-loader-hoc.jsx'; +import ProjectLoaderHOC from './project-loader-hoc.jsx'; import styles from './blocks-only.css'; diff --git a/src/examples/compatibility-testing.jsx b/src/playground/compatibility-testing.jsx similarity index 97% rename from src/examples/compatibility-testing.jsx rename to src/playground/compatibility-testing.jsx index 3fa8e71d94e34e4722ec1a1f329c9df46de2688c..513758023df0209ebdd0045d2a71b753fab71411 100644 --- a/src/examples/compatibility-testing.jsx +++ b/src/playground/compatibility-testing.jsx @@ -7,7 +7,7 @@ import Controls from '../containers/controls.jsx'; import Stage from '../containers/stage.jsx'; import Box from '../components/box/box.jsx'; import GUI from '../containers/gui.jsx'; -import ProjectLoaderHOC from '../lib/project-loader-hoc.jsx'; +import ProjectLoaderHOC from './project-loader-hoc.jsx'; const mapStateToProps = state => ({vm: state.vm}); diff --git a/src/index.css b/src/playground/index.css similarity index 100% rename from src/index.css rename to src/playground/index.css diff --git a/src/index.ejs b/src/playground/index.ejs similarity index 100% rename from src/index.ejs rename to src/playground/index.ejs diff --git a/src/index.jsx b/src/playground/index.jsx similarity index 76% rename from src/index.jsx rename to src/playground/index.jsx index 114c45ce0ad6194d76270bee6e79bea378ecb9ec..0574c8d09b04d885c2c13773ea11d46b04a8c009 100644 --- a/src/index.jsx +++ b/src/playground/index.jsx @@ -3,10 +3,10 @@ import React from 'react'; import ReactDOM from 'react-dom'; import Modal from 'react-modal'; -import analytics from './lib/analytics'; -import AppStateHOC from './lib/app-state-hoc.jsx'; -import GUI from './containers/gui.jsx'; -import ProjectLoaderHOC from './lib/project-loader-hoc.jsx'; +import analytics from '../lib/analytics'; +import AppStateHOC from '../lib/app-state-hoc.jsx'; +import GUI from '../containers/gui.jsx'; +import ProjectLoaderHOC from './project-loader-hoc.jsx'; import styles from './index.css'; diff --git a/src/playground/intl.js b/src/playground/intl.js new file mode 100644 index 0000000000000000000000000000000000000000..bc427c402a022d03fa3bd64b0a6ffd6ff5b5afbf --- /dev/null +++ b/src/playground/intl.js @@ -0,0 +1,25 @@ +import {addLocaleData} from 'react-intl'; +import defaultsDeep from 'lodash.defaultsdeep'; + +import localeData from 'scratch-l10n'; +import guiMessages from 'scratch-l10n/locales/gui-msgs'; +import paintMessages from 'scratch-l10n/locales/paint-msgs'; +import penMessages from 'scratch-l10n/locales/pen-msgs'; + +const combinedMessages = defaultsDeep({}, guiMessages.messages, paintMessages.messages, penMessages.messages); + +Object.keys(localeData).forEach(locale => { + // TODO: will need to handle locales not in the default intl - see www/custom-locales + addLocaleData(localeData[locale].localeData); +}); + +const intlDefault = { + defaultLocale: 'en', + locale: 'en', + messages: combinedMessages.en.messages +}; + +export { + intlDefault as default, + combinedMessages +}; diff --git a/src/examples/player.css b/src/playground/player.css similarity index 100% rename from src/examples/player.css rename to src/playground/player.css diff --git a/src/examples/player.jsx b/src/playground/player.jsx similarity index 97% rename from src/examples/player.jsx rename to src/playground/player.jsx index ab50527cde1ae1d4be7788e7545397ff48b3700c..30b18e8ed89efc3e8c373c9882588c0130b98b42 100644 --- a/src/examples/player.jsx +++ b/src/playground/player.jsx @@ -7,7 +7,7 @@ import Controls from '../containers/controls.jsx'; import Stage from '../containers/stage.jsx'; import Box from '../components/box/box.jsx'; import GUI from '../containers/gui.jsx'; -import ProjectLoaderHOC from '../lib/project-loader-hoc.jsx'; +import ProjectLoaderHOC from './project-loader-hoc.jsx'; import './player.css'; diff --git a/src/lib/project-loader-hoc.jsx b/src/playground/project-loader-hoc.jsx similarity index 96% rename from src/lib/project-loader-hoc.jsx rename to src/playground/project-loader-hoc.jsx index 5ccb382b2560f27756bb04276ab7eaff3440e8a8..3ebacee17ff8d4b3d40c704c664019a150f30d22 100644 --- a/src/lib/project-loader-hoc.jsx +++ b/src/playground/project-loader-hoc.jsx @@ -1,8 +1,8 @@ import React from 'react'; -import analytics from './analytics'; -import log from './log'; -import storage from './storage'; +import analytics from '../lib/analytics'; +import log from '../lib/log'; +import storage from '../lib/storage'; /* Higher Order Component to provide behavior for loading projects by id from * the window's hash (#this part in the url) diff --git a/src/reducers/intl.js b/src/reducers/intl.js index 15a2d307b885917cf75e363bf9b484d412edd2fb..8c49ee10475c5a960c35d6eba723203dbb772091 100644 --- a/src/reducers/intl.js +++ b/src/reducers/intl.js @@ -1,36 +1,14 @@ -import {addLocaleData} from 'react-intl'; -import {updateIntl as superUpdateIntl} from 'react-intl-redux'; -import {IntlProvider, intlReducer} from 'react-intl-redux'; -import defaultsDeep from 'lodash.defaultsdeep'; - -import localeData from 'scratch-l10n'; -import guiMessages from 'scratch-l10n/locales/gui-msgs'; -import paintMessages from 'scratch-l10n/locales/paint-msgs'; -import penMessages from 'scratch-l10n/locales/pen-msgs'; - -const combinedMessages = defaultsDeep({}, guiMessages.messages, paintMessages.messages, penMessages.messages); - -Object.keys(localeData).forEach(locale => { - // TODO: will need to handle locales not in the default intl - see www/custom-locales - addLocaleData(localeData[locale].localeData); -}); +import {intlReducer} from 'react-intl-redux'; const intlInitialState = { intl: { defaultLocale: 'en', locale: 'en', - messages: combinedMessages.en.messages + messages: {} } }; -const updateIntl = locale => superUpdateIntl({ - locale: locale, - messages: combinedMessages[locale].messages || combinedMessages.en.messages -}); - export { intlReducer as default, - IntlProvider, - intlInitialState, - updateIntl + intlInitialState }; diff --git a/test/unit/util/project-loader-hoc.test.jsx b/test/unit/util/project-loader-hoc.test.jsx index 5acde098e53b8630f1a9b2dbc74177faadcb70d8..997224e7415a2e771dac892ac8d2e8fe80d26ee6 100644 --- a/test/unit/util/project-loader-hoc.test.jsx +++ b/test/unit/util/project-loader-hoc.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import ProjectLoaderHOC from '../../../src/lib/project-loader-hoc.jsx'; +import ProjectLoaderHOC from '../../../src/playground/project-loader-hoc.jsx'; import storage from '../../../src/lib/storage'; import {mount} from 'enzyme'; diff --git a/webpack.config.js b/webpack.config.js index 389cf8abd6db12e1deb277d680469a688d518cb6..4a94a9a0dc0a4ab975c784983bc6436b6aa7a526 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -19,10 +19,10 @@ module.exports = { devtool: 'cheap-module-source-map', entry: { lib: ['react', 'react-dom'], - gui: './src/index.jsx', - blocksonly: './src/examples/blocks-only.jsx', - compatibilitytesting: './src/examples/compatibility-testing.jsx', - player: './src/examples/player.jsx' + gui: './src/playground/index.jsx', + blocksonly: './src/playground/blocks-only.jsx', + compatibilitytesting: './src/playground/compatibility-testing.jsx', + player: './src/playground/player.jsx' }, output: { path: path.resolve(__dirname, 'build'), @@ -82,24 +82,24 @@ module.exports = { }), new HtmlWebpackPlugin({ chunks: ['lib', 'gui'], - template: 'src/index.ejs', + template: 'src/playground/index.ejs', title: 'Scratch 3.0 GUI' }), new HtmlWebpackPlugin({ chunks: ['lib', 'blocksonly'], - template: 'src/index.ejs', + template: 'src/playground/index.ejs', filename: 'blocks-only.html', title: 'Scratch 3.0 GUI: Blocks Only Example' }), new HtmlWebpackPlugin({ chunks: ['lib', 'compatibilitytesting'], - template: 'src/index.ejs', + template: 'src/playground/index.ejs', filename: 'compatibility-testing.html', title: 'Scratch 3.0 GUI: Compatibility Testing' }), new HtmlWebpackPlugin({ chunks: ['lib', 'player'], - template: 'src/index.ejs', + template: 'src/playground/index.ejs', filename: 'player.html', title: 'Scratch 3.0 GUI: Player Example' }),