Skip to content

Commit

Permalink
Merge branch 'next' into slide-function-component
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviertassinari authored Apr 18, 2019
2 parents 3df7d17 + ccc466a commit f4316db
Show file tree
Hide file tree
Showing 24 changed files with 1,690 additions and 4 deletions.
4 changes: 2 additions & 2 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
/coverage
/docs/export
/examples/create-react-app*/src/serviceWorker.js
/examples/create-react-app-with-flow/flow
/examples/create-react-app-with-flow/flow-typed
/examples/preact-next/config
/examples/preact-next/scripts
/examples/gatsby/public
/packages/babel-plugin-unwrap-createStyles/test/__fixtures__/
/packages/material-ui-codemod/lib
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,22 @@ We hope 2-3 weeks of beta will be enough. We plan on releasing v4 stable in May.
- [DialogActions] Rename the `action` CSS class `spacing`.
- [ExpansionPanelActions] Rename the `action` CSS class `spacing`.

- [Tooltip] Convert to function component (#15291) @joshwooding
The child of the `Tooltip` needs to be able to hold a ref

```diff
class Component extends React.Component {
render() {
return <div />
}
}
-const MyComponent = props => <div {...props} />
+const MyComponent = React.forwardRef((props, ref) => <div ref={ref} {...props} />);
<Tooltip><Component /></Tooltip>
<Tooltip><MyComponent /></Tooltip>
<Tooltip><div /></Tooltip>
```

#### Changes

- [ScrollbarSize] Convert to function component (#15233) @joshwooding
Expand Down
31 changes: 31 additions & 0 deletions docs/src/pages/demos/selection-controls/Switches.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import Switch from '@material-ui/core/Switch';

function Switches() {
const [state, setState] = React.useState({
checkedA: true,
checkedB: true,
});

const handleChange = (name: string) => (event: React.ChangeEvent<HTMLInputElement>) => {
setState({ ...state, [name]: event.target.checked });
};

return (
<div>
<Switch checked={state.checkedA} onChange={handleChange('checkedA')} value="checkedA" />
<Switch
checked={state.checkedB}
onChange={handleChange('checkedB')}
value="checkedB"
color="primary"
/>
<Switch value="checkedC" />
<Switch disabled value="checkedD" />
<Switch disabled checked value="checkedE" />
<Switch defaultChecked value="checkedF" color="default" />
</div>
);
}

export default Switches;
18 changes: 17 additions & 1 deletion docs/src/pages/guides/migration-v3/migration-v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ You should be able to move the custom styles to the root class key.

### Modal

- [Modal] Ignore event.defaultPrevented (#14991) @oliviertassinari
- [Modal] event.defaultPrevented is now ignored.

The new logic closes the Modal even if `event.preventDefault()` is called on the key down escape event.
`event.preventDefault()` is meant to stop default behaviors like clicking a checkbox to check it, hitting a button to submit a form, and hitting left arrow to move the cursor in a text input etc.
Expand All @@ -356,4 +356,20 @@ You should be able to move the custom styles to the root class key.
<Slide><Component /></Slide>
<Slide><MyComponent /></Slide>
<Slide><div /></Slide>

### Tooltip

- [Tooltip] The child needs to be able to hold a ref.

```diff
class Component extends React.Component {
render() {
return <div />
}
}
-const MyComponent = props => <div {...props} />
+const MyComponent = React.forwardRef((props, ref) => <div ref={ref} {...props} />);
<Tooltip><Component /></Tooltip>
<Tooltip><MyComponent /></Tooltip>
<Tooltip><div /></Tooltip>
```
27 changes: 27 additions & 0 deletions examples/preact-next/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# IDEs and editors
/.idea
/.vscode

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
32 changes: 32 additions & 0 deletions examples/preact-next/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Preact v4-alpha example

## How to use

Download the example [or clone the repo](https://github.com/mui-org/material-ui):

```sh
curl https://codeload.github.com/mui-org/material-ui/tar.gz/next | tar -xz --strip=2 material-ui-next/examples/preact-next
cd preact-next
```

Install it and run:

```sh
npm install
npm run start
```

## The idea behind the example

[Preact](https://github.com/developit/preact) is a fast 3kB alternative to React with the same modern API.

This example uses an ejected version of CRA.
It's ejected to change the webpack configuration:

```js
alias: {
// Use Preact instead of React.
'react': 'preact/compat',
'react-dom': 'preact/compat',
}
```
91 changes: 91 additions & 0 deletions examples/preact-next/config/env.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
'use strict';

const fs = require('fs');
const path = require('path');
const paths = require('./paths');

// Make sure that including paths.js after env.js will read .env variables.
delete require.cache[require.resolve('./paths')];

const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
throw new Error('The NODE_ENV environment variable is required but was not specified.');
}

// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
var dotenvFiles = [
`${paths.dotenv}.${NODE_ENV}.local`,
`${paths.dotenv}.${NODE_ENV}`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
paths.dotenv,
].filter(Boolean);

// Load environment variables from .env* files. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set. Variable expansion is supported in .env files.
// https://github.com/motdotla/dotenv
// https://github.com/motdotla/dotenv-expand
dotenvFiles.forEach(dotenvFile => {
if (fs.existsSync(dotenvFile)) {
require('dotenv-expand')(
require('dotenv').config({
path: dotenvFile,
}),
);
}
});

// We support resolving modules according to `NODE_PATH`.
// This lets you use absolute paths in imports inside large monorepos:
// https://github.com/facebook/create-react-app/issues/253.
// It works similar to `NODE_PATH` in Node itself:
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
// We also resolve them to make sure all tools using them work consistently.
const appDirectory = fs.realpathSync(process.cwd());
process.env.NODE_PATH = (process.env.NODE_PATH || '')
.split(path.delimiter)
.filter(folder => folder && !path.isAbsolute(folder))
.map(folder => path.resolve(appDirectory, folder))
.join(path.delimiter);

// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
// injected into the application via DefinePlugin in Webpack configuration.
const REACT_APP = /^REACT_APP_/i;

function getClientEnvironment(publicUrl) {
const raw = Object.keys(process.env)
.filter(key => REACT_APP.test(key))
.reduce(
(env, key) => {
env[key] = process.env[key];
return env;
},
{
// Useful for determining whether we’re running in production mode.
// Most importantly, it switches React into the correct mode.
NODE_ENV: process.env.NODE_ENV || 'development',
// Useful for resolving the correct path to static assets in `public`.
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
// This should only be used as an escape hatch. Normally you would put
// images into the `src` and `import` them in code to get their paths.
PUBLIC_URL: publicUrl,
},
);
// Stringify all values so we can feed into Webpack DefinePlugin
const stringified = {
'process.env': Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key]);
return env;
}, {}),
};

return { raw, stringified };
}

module.exports = getClientEnvironment;
14 changes: 14 additions & 0 deletions examples/preact-next/config/jest/cssTransform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict';

// This is a custom Jest transformer turning style imports into empty objects.
// http://facebook.github.io/jest/docs/en/webpack.html

module.exports = {
process() {
return 'module.exports = {};';
},
getCacheKey() {
// The output is always the same.
return 'cssTransform';
},
};
31 changes: 31 additions & 0 deletions examples/preact-next/config/jest/fileTransform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';

const path = require('path');

// This is a custom Jest transformer turning file imports into filenames.
// http://facebook.github.io/jest/docs/en/webpack.html

module.exports = {
process(src, filename) {
const assetFilename = JSON.stringify(path.basename(filename));

if (filename.match(/\.svg$/)) {
return `const React = require('react');
module.exports = {
__esModule: true,
default: ${assetFilename},
ReactComponent: React.forwardRef((props, ref) => ({
$$typeof: Symbol.for('react.element'),
type: 'svg',
ref: ref,
key: null,
props: Object.assign({}, props, {
children: ${assetFilename}
})
})),
};`;
}

return `module.exports = ${assetFilename};`;
},
};
85 changes: 85 additions & 0 deletions examples/preact-next/config/paths.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
'use strict';

const path = require('path');
const fs = require('fs');
const url = require('url');

// Make sure any symlinks in the project folder are resolved:
// https://github.com/facebook/create-react-app/issues/637
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);

const envPublicUrl = process.env.PUBLIC_URL;

function ensureSlash(inputPath, needsSlash) {
const hasSlash = inputPath.endsWith('/');
if (hasSlash && !needsSlash) {
return inputPath.substr(0, inputPath.length - 1);
} else if (!hasSlash && needsSlash) {
return `${inputPath}/`;
} else {
return inputPath;
}
}

const getPublicUrl = appPackageJson => envPublicUrl || require(appPackageJson).homepage;

// We use `PUBLIC_URL` environment variable or "homepage" field to infer
// "public path" at which the app is served.
// Webpack needs to know it to put the right <script> hrefs into HTML even in
// single-page apps that may serve index.html for nested URLs like /todos/42.
// We can't use a relative path in HTML because we don't want to load something
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
function getServedPath(appPackageJson) {
const publicUrl = getPublicUrl(appPackageJson);
const servedUrl = envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/');
return ensureSlash(servedUrl, true);
}

const moduleFileExtensions = [
'web.mjs',
'mjs',
'web.js',
'js',
'web.ts',
'ts',
'web.tsx',
'tsx',
'json',
'web.jsx',
'jsx',
];

// Resolve file paths in the same order as webpack
const resolveModule = (resolveFn, filePath) => {
const extension = moduleFileExtensions.find(extension =>
fs.existsSync(resolveFn(`${filePath}.${extension}`)),
);

if (extension) {
return resolveFn(`${filePath}.${extension}`);
}

return resolveFn(`${filePath}.js`);
};

// config after eject: we're in ./config/
module.exports = {
dotenv: resolveApp('.env'),
appPath: resolveApp('.'),
appBuild: resolveApp('build'),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveModule(resolveApp, 'src/index'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
appTsConfig: resolveApp('tsconfig.json'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
proxySetup: resolveApp('src/setupProxy.js'),
appNodeModules: resolveApp('node_modules'),
publicUrl: getPublicUrl(resolveApp('package.json')),
servedPath: getServedPath(resolveApp('package.json')),
};

module.exports.moduleFileExtensions = moduleFileExtensions;
Loading

0 comments on commit f4316db

Please sign in to comment.