Skip to content

Commit

Permalink
[icons] New iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviertassinari committed Jul 18, 2018
1 parent 6b4942b commit 4ba8871
Show file tree
Hide file tree
Showing 65 changed files with 474 additions and 139 deletions.
13 changes: 12 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,16 @@
]
},
"development": {
"sourceMaps": "both"
"plugins": [
[
"module-resolver",
{
"alias": {
"modules": "./modules",
}
}
]
]
},
"docs-development": {
"plugins": [
Expand All @@ -40,6 +49,7 @@
"@material-ui/icons": "./packages/material-ui-icons/src",
"@material-ui/lab": "./packages/material-ui-lab/src",
"docs": "./docs",
"modules": "./modules",
"pages": "./pages"
}
}
Expand All @@ -58,6 +68,7 @@
"@material-ui/icons": "./packages/material-ui-icons/src",
"@material-ui/lab": "./packages/material-ui-lab/src",
"docs": "./docs",
"modules": "./modules",
"pages": "./pages"
}
}
Expand Down
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
/packages/material-ui-codemod/src/*/*.test
/packages/material-ui-codemod/src/*/*.test.js
/packages/material-ui-icons/src
/packages/material-ui-icons/test/fixtures
/packages/material-ui-icons/fixtures
/packages/material-ui-icons/templateSvgIcon.js
/tmp
build
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/coverage
/docs/export
/packages/material-ui-codemod/lib
/packages/material-ui-icons/material-design-icons
/packages/material-ui-icons/material-io-tools-icons
/test/regressions/screenshots
/test/selenium-output
/tmp
Expand Down
9 changes: 2 additions & 7 deletions docs/src/modules/components/Notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'isomorphic-fetch';
import React from 'react';
import Button from '@material-ui/core/Button';
import Snackbar from '@material-ui/core/Snackbar';
import sleep from 'modules/waterfall/sleep';

function getLastSeenNotification() {
const seen = document.cookie.replace(
Expand All @@ -13,18 +14,12 @@ function getLastSeenNotification() {
return seen === '' ? 0 : parseInt(seen, 10);
}

function pause(timeout) {
return new Promise(accept => {
setTimeout(accept, timeout);
});
}

let messages = null;

async function getMessages() {
try {
if (!messages) {
await pause(1e3); // Soften the pressure on the main thread.
await sleep(1e3); // Soften the pressure on the main thread.
const result = await fetch(
'https://raw.githubusercontent.com/mui-org/material-ui/master/docs/notifications.json',
);
Expand Down
35 changes: 35 additions & 0 deletions docs/src/pages/style/icons/SvgMaterialIconsAll.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';

const requireIcons = require.context('../../../../../packages/material-ui-icons/src', true, /js$/);

const styles = theme => ({
root: {
color: theme.palette.text.primary,
maxHeight: 300,
overflow: 'auto',
},
});

function SvgMaterialIconsAll(props) {
const { classes } = props;
return (
<div className={classes.root}>
{requireIcons.keys().map(key => {
if (key === './index.js' || key === './utils/createSvgIcon.js') {
return null;
}

const Icon = requireIcons(key).default;
return <Icon key={key} />;
})}
</div>
);
}

SvgMaterialIconsAll.propTypes = {
classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(SvgMaterialIconsAll);
47 changes: 47 additions & 0 deletions modules/waterfall/Batcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Inspired by http://caolan.github.io/async/docs.html#cargo
// The main difference is that we have a timeout.
class Batcher {
pendingEntries = [];

timeout = null;

context = {};

constructor(worker, options = {}) {
// max waiting time before flushing the pending entries (process them)
this.maxWait = options.maxWait || 1000;
// max number of entries in the queue before flushing them (process them)
this.maxItems = options.maxItems || 100;
this.worker = worker;
}

// public method
push(entries, contextItem) {
this.context = contextItem;
this.pendingEntries = this.pendingEntries.concat(entries);

if (this.pendingEntries.length >= this.maxItems) {
return this.sendItems();
}

clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.sendItems();
}, this.maxWait);

return null;
}

sendItems() {
const pendingEntries = this.pendingEntries.splice(0); // Transfer the item to the job.
clearTimeout(this.timeout);
return this.worker(pendingEntries, this.context);
}

clear() {
clearTimeout(this.timeout);
this.pendingEntries = [];
}
}

export default Batcher;
59 changes: 59 additions & 0 deletions modules/waterfall/Queue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import waitUntil from './waitUntil';

class Queue {
pendingEntries = [];

inFlight = 0;

err = null;

constructor(worker, options = {}) {
this.worker = worker;
this.concurrency = options.concurrency || 1;
}

push = entries => {
this.pendingEntries = this.pendingEntries.concat(entries);
this.process();
};

process = () => {
const scheduled = this.pendingEntries.splice(0, this.concurrency - this.inFlight);
this.inFlight += scheduled.length;
scheduled.forEach(async task => {
try {
await this.worker(task);
} catch (err) {
this.err = err;
} finally {
this.inFlight -= 1;
}

if (this.pendingEntries.length > 0) {
this.process();
}
});
};

wait = (options = {}) => {
return waitUntil(
() => {
if (this.err) {
this.pendingEntries = [];
throw this.err;
}

return {
predicate: options.empty
? this.inFlight === 0 && this.pendingEntries.length === 0
: this.concurrency > this.pendingEntries.length,
};
},
{
delay: 50,
},
);
};
}

export default Queue;
3 changes: 3 additions & 0 deletions modules/waterfall/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Waterfall

A set of utility functions for handling async/await at scale.
8 changes: 8 additions & 0 deletions modules/waterfall/forEach.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
async function forEach(array, iteratee) {
for (let i = 0; i < array.length; i += 1) {
// eslint-disable-next-line no-await-in-loop
await iteratee(array[i], i);
}
}

export default forEach;
126 changes: 126 additions & 0 deletions modules/waterfall/metric.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// The API is inspired by console.time
// The implementation is isomorphic.
import warning from 'warning';

const times = new Map();

const implementations = {
mark: {
start: name => {
times.set(name, performance.now());
performance.mark(`metric_${name}_start`);
},
end: name => {
const endMark = `metric_${name}_end`;
performance.mark(endMark);
const startMark = `metric_${name}_start`;
performance.measure(name, startMark, endMark);
const duration = performance.getEntriesByName(name)[0].duration;
return duration;
},
},
now: {
start: name => {
times.set(name, performance.now());
},
end: name => {
const time = times.get(name);
const duration = performance.now() - time;
return duration;
},
},
hrtime: {
start: name => {
// https://nodejs.org/api/process.html#process_process_hrtime_time
times.set(name, process.hrtime());
},
end: name => {
const time = times.get(name);
const durations = process.hrtime(time);
const duration = durations[0] / 1e3 + durations[1] / 1e6;
return duration;
},
},
};

let getImplementationCache;

function getImplementation() {
if (getImplementationCache) {
return getImplementationCache;
}

if (typeof performance !== 'undefined' && performance.mark) {
getImplementationCache = implementations.mark;
} else if (typeof performance !== 'undefined' && performance.now) {
getImplementationCache = implementations.now;
} else if (process.hrtime) {
getImplementationCache = implementations.hrtime;
} else {
throw new Error('No performance API available');
}

return getImplementationCache;
}

class Metric {
/**
* Call to begin a measurement.
*/
static start(name) {
warning(!times.get(name), 'Recording already started');
getImplementation().start(name);
}

/**
* Returns the duration of the timing metric. The unit is milliseconds.
* @type {number}
*/
static end(name) {
if (!times.get(name)) {
throw new Error(`No such name '${name}' for metric`);
}

const duration = getImplementation().end(name);
times.delete(name);
return duration;
}

name = '';

/**
* @param {string} name A name for the metric.
*/
constructor(name) {
if (!name) {
throw new Error('Please provide a metric name');
}

this.name = name;
}

/**
* Call to begin a measurement.
*/
start(name) {
if (name) {
throw new Error('The name argument is not supported');
}

Metric.start(this.name);
}

/**
* Returns the duration of the timing metric. The unit is milliseconds.
* @type {number}
*/
end(name) {
if (name) {
throw new Error('The name argument is not supported');
}

return Metric.end(this.name);
}
}

export default Metric;
34 changes: 34 additions & 0 deletions modules/waterfall/retry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Inspired by https://github.com/zeit/async-retry
// Without the retry dependency (1 kB gzipped +)
async function retry(tryFunction, options = {}) {
const { retries = 3 } = options;

let tries = 0;
let output = null;
let exitErr = null;

const bail = err => {
exitErr = err;
};

while (tries < retries) {
tries += 1;
try {
// eslint-disable-next-line no-await-in-loop
output = await tryFunction({ tries, bail });
break;
} catch (err) {
if (tries >= retries) {
throw err;
}
}
}

if (exitErr) {
throw exitErr;
}

return output;
}

export default retry;
Loading

0 comments on commit 4ba8871

Please sign in to comment.