Completely updated React, fixed #11, (hopefully)

This commit is contained in:
2018-03-04 19:11:49 -05:00
parent 6e0afd6e2a
commit 34e5f5139a
13674 changed files with 333464 additions and 473223 deletions

View File

@@ -1,7 +1,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import { findDOMNode } from 'react-dom';
import EventListener from 'react-event-listener';
import ownerDocument from 'dom-helpers/ownerDocument';
const isDescendant = (el, target) => {
if (target !== null && target.parentNode) {
@@ -26,8 +27,9 @@ class ClickAwayListener extends React.Component {
// IE11 support, which trigger the handleClickAway even after the unbind
if (this.mounted) {
const el = findDOMNode(this);
const doc = ownerDocument(el);
if (event.target instanceof HTMLElement && document.documentElement && document.documentElement.contains(event.target) && !isDescendant(el, event.target)) {
if (doc.documentElement && doc.documentElement.contains(event.target) && !isDescendant(el, event.target)) {
this.props.onClickAway(event);
}
}
@@ -55,4 +57,9 @@ class ClickAwayListener extends React.Component {
}
}
ClickAwayListener.propTypes = process.env.NODE_ENV !== "production" ? {
children: PropTypes.node.isRequired,
onClickAway: PropTypes.func.isRequired
} : {};
export default ClickAwayListener;

View File

@@ -2,5 +2,5 @@ export default function addEventListener(
node: Node,
event: string,
handler: (e: Event) => never,
capture?: boolean
capture?: boolean,
): { remove(): void };

View File

@@ -1,11 +1,8 @@
import addEventListener from 'dom-helpers/events/on';
import removeEventListener from 'dom-helpers/events/off';
export default function (node, event, handler, capture) {
addEventListener(node, event, handler, capture);
node.addEventListener(event, handler, capture);
return {
remove() {
removeEventListener(node, event, handler, capture);
node.removeEventListener(event, handler, capture);
}
};
}

View File

@@ -1,4 +1,5 @@
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
import _Object$keys from 'babel-runtime/core-js/object/keys';
import _extends from 'babel-runtime/helpers/extends';
// This module is based on https://github.com/airbnb/prop-types-exact repository.
// However, in order to reduce the number of dependencies and to remove some extra safe checks
@@ -10,7 +11,7 @@ export default function exactProp(propTypes, componentNameInError) {
return _extends({}, propTypes, {
// eslint-disable-next-line prefer-arrow-callback
[specialProperty]: props => {
const unknownProps = Object.keys(props).filter(prop => !propTypes.hasOwnProperty(prop));
const unknownProps = _Object$keys(props).filter(prop => !propTypes.hasOwnProperty(prop));
if (unknownProps.length > 0) {
return new TypeError(`${componentNameInError}: unknown props found: ${unknownProps.join(', ')}. Please remove the unknown properties.`);
}

View File

@@ -1,7 +1,7 @@
export function capitalizeFirstLetter(str: string): string;
export function contains(obj: Object, pred: Object): boolean;
export function capitalize(str: string): string;
export function contains<O1 extends O2, O2>(obj: O1, pred: O2): boolean;
export function findIndex(arr: any[], pred: any): number;
export function find<T>(arr: T[], pred: any): T;
export function createChainedFunction(
...funcs: Function[]
): (...args: any[]) => never;
export function createChainedFunction(...funcs: ChainedFunction[]): (...args: any[]) => never;
type ChainedFunction = ((...args: any[]) => void) | undefined | null;

View File

@@ -1,15 +1,18 @@
import _Object$keys from 'babel-runtime/core-js/object/keys';
// weak
import warning from 'warning';
export function capitalizeFirstLetter(string) {
warning(typeof string === 'string', 'Material-UI: capitalizeFirstLetter(string) expects a string argument.');
export function capitalize(string) {
if (process.env.NODE_ENV !== 'production' && typeof string !== 'string') {
throw new Error('Material-UI: capitalize(string) expects a string argument.');
}
return string.charAt(0).toUpperCase() + string.slice(1);
}
export function contains(obj, pred) {
return Object.keys(pred).every(key => {
return _Object$keys(pred).every(key => {
return obj.hasOwnProperty(key) && obj[key] === pred[key];
});
}
@@ -46,7 +49,7 @@ export function find(arr, pred) {
*/
export function createChainedFunction(...funcs) {
return funcs.filter(func => func != null).reduce((acc, func) => {
warning(typeof func === 'function', 'Material-UI: invalid Argument Type, must only provide functions, undefined, or null.');
process.env.NODE_ENV !== "production" ? warning(typeof func === 'function', 'Material-UI: invalid Argument Type, must only provide functions, undefined, or null.') : void 0;
return function chainedFunction(...args) {
acc.apply(this, args);

View File

@@ -6,7 +6,7 @@ export function detectKeyboardFocus(
keyboardFocusMaxCheckTimes: number;
},
element: Element,
cb: Function,
attempt: number
): never;
export function listenForFocusKeys(): never;
cb: () => void,
attempt: number,
): void;
export function listenForFocusKeys(window: Window): void;

View File

@@ -3,10 +3,9 @@
import keycode from 'keycode';
import warning from 'warning';
import contains from 'dom-helpers/query/contains';
import addEventListener from '../utils/addEventListener';
import ownerDocument from 'dom-helpers/ownerDocument';
const internal = {
listening: false,
focusKeyPressed: false
};
@@ -19,11 +18,13 @@ export function focusKeyPressed(pressed) {
}
export function detectKeyboardFocus(instance, element, callback, attempt = 1) {
warning(instance.keyboardFocusCheckTime, 'Material-UI: missing instance.keyboardFocusCheckTime');
warning(instance.keyboardFocusMaxCheckTimes, 'Material-UI: missing instance.keyboardFocusMaxCheckTimes');
process.env.NODE_ENV !== "production" ? warning(instance.keyboardFocusCheckTime, 'Material-UI: missing instance.keyboardFocusCheckTime') : void 0;
process.env.NODE_ENV !== "production" ? warning(instance.keyboardFocusMaxCheckTimes, 'Material-UI: missing instance.keyboardFocusMaxCheckTimes') : void 0;
instance.keyboardFocusTimeout = setTimeout(() => {
if (focusKeyPressed() && (document.activeElement === element || contains(element, document.activeElement))) {
const doc = ownerDocument(element);
if (focusKeyPressed() && (doc.activeElement === element || contains(element, doc.activeElement))) {
callback();
} else if (attempt < instance.keyboardFocusMaxCheckTimes) {
detectKeyboardFocus(instance, element, callback, attempt + 1);
@@ -37,15 +38,15 @@ function isFocusKey(event) {
return FOCUS_KEYS.indexOf(keycode(event)) !== -1;
}
export function listenForFocusKeys() {
// It's a singleton, we only need to listen once.
// Also, this logic is client side only, we don't need a teardown.
if (!internal.listening) {
addEventListener(window, 'keyup', event => {
if (isFocusKey(event)) {
internal.focusKeyPressed = true;
}
});
internal.listening = true;
const handleKeyUpEvent = event => {
if (isFocusKey(event)) {
internal.focusKeyPressed = true;
}
};
export function listenForFocusKeys(win) {
// The event listener will only be added once per window.
// Duplicate event listeners will be ignored by addEventListener.
// Also, this logic is client side only, we don't need a teardown.
win.addEventListener('keyup', handleKeyUpEvent);
}

View File

@@ -1,3 +0,0 @@
export function ariaHidden(show: boolean, node: Node): never;
export function hideSiblings(container: Element, mountNode: Node): never;
export function showSiblings(container: Element, mountNode: Node): never;

View File

@@ -1,33 +0,0 @@
// weak
const BLACKLIST = ['template', 'script', 'style'];
const isHidable = ({ nodeType, tagName }) => nodeType === 1 && BLACKLIST.indexOf(tagName.toLowerCase()) === -1;
const siblings = (container, mount, cb) => {
mount = [].concat(mount); // eslint-disable-line no-param-reassign
[].forEach.call(container.children, node => {
if (mount.indexOf(node) === -1 && isHidable(node)) {
cb(node);
}
});
};
export function ariaHidden(show, node) {
if (!node) {
return;
}
if (show) {
node.setAttribute('aria-hidden', 'true');
} else {
node.removeAttribute('aria-hidden');
}
}
export function hideSiblings(container, mountNode) {
siblings(container, mountNode, node => ariaHidden(true, node));
}
export function showSiblings(container, mountNode) {
siblings(container, mountNode, node => ariaHidden(false, node));
}

View File

@@ -1,4 +1,15 @@
export function cloneChildrenWithClassName<T>(
children: React.ReactNode,
className: string
): T[];
import * as React from 'react';
import { StandardProps } from '../';
export function cloneChildrenWithClassName<T>(children: React.ReactNode, className: string): T[];
type NamedMuiComponent = React.ComponentType<{}> & { muiName: string };
interface NamedMuiElement {
type: NamedMuiComponent;
props: StandardProps<{}, never>;
key: string | number | null;
}
export function isMuiElement(element: any, muiNames: string[]): element is NamedMuiElement;
export function isMuiComponent(element: any, muiNames: string[]): element is NamedMuiComponent;

View File

@@ -1,19 +1,20 @@
/* eslint-disable import/prefer-default-export */
import { cloneElement, Children, isValidElement } from 'react';
import React from 'react';
import classNames from 'classnames';
export function cloneChildrenWithClassName(children, className) {
return Children.map(children, child => {
return isValidElement(child) && cloneElement(child, {
className: child.props.hasOwnProperty('className') ? `${child.props.className} ${className}` : className
return React.Children.map(children, child => {
return React.isValidElement(child) && React.cloneElement(child, {
className: classNames(child.props.className, className)
});
});
}
export function isMuiElement(element, muiNames) {
return isValidElement(element) && muiNames.indexOf(element.type.muiName) !== -1;
return React.isValidElement(element) && muiNames.indexOf(element.type.muiName) !== -1;
}
export function isMuiComponent(element, muiNames) {

View File

@@ -8,14 +8,20 @@ export interface WithWidthProps {
width: Breakpoint;
}
export function isWidthUp(
export function isWidthDown(
breakpoint: Breakpoint,
screenWidth: number,
inclusive?: boolean
screenWidth: Breakpoint,
inclusive?: boolean,
): boolean;
export default function withWidth<P = {}>(
options?: WithWidthOptions
): (
component: React.ComponentType<P>
) => React.ComponentClass<P & WithWidthProps>;
export function isWidthUp(
breakpoint: Breakpoint,
screenWidth: Breakpoint,
inclusive?: boolean,
): boolean;
export default function withWidth(
options?: WithWidthOptions,
): <P>(
component: React.ComponentType<P & WithWidthProps>,
) => React.ComponentClass<P & Partial<WithWidthProps>>;

View File

@@ -1,59 +1,37 @@
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
// weak
// flow sanity check (DO NOT DELETE) https://flow.org/try/#0JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wG4AoUSWOGATzCTgG84BhXSAOyS5gBUGTAL5xsuAkXQwy5OQHp5cALSq16jZuVwdccorgB3YDAAW-U0hBMAEgHk25JAA9qWAK5cMwCFyMnzS2sAHgAFHDAAZwAuFmEAPgAKcl12Tl9eGFiOcAy+QUZg1jMrJFi7ACMAKyQMOFEAMjhwiCj4gBpyAEps9J58oTCIyPiWOR00ABsUSMi4AHUAi1K4FxheABM55GkAOhzuTKHWyPaWWiCyuEqauoSx1KIuDaQoRK6H1LgiGHcoP2CBzy8GYuzBZmAkV2YGGohK1gAvMwIVDIjAUOtdvCkKJ5PEKKlhAT6ilvkhfv8FktLuRhAolFpGUy1PolMYzMtrHAAKqRFAAcyQ5CmMzmAEFVs51s9tsQYPs+kdipdytVavBGiwULEuO4QBVXmcKjq9QaoPdmHS0L40XBOUgNkD+vAEf4OZdEmKuhQDPMmBtfPh4DwHbQIHAwKK4MA-AADbGx1YAN14Fwg7n5pjgsYAsnQnZlE0QAI7uYBEOYmXbkYL2x2KvhwFBIgCMogqSIATLj4vSVMyB6lWW7TIsNmY4PZHC43LQhHAAEJSADWkBjLoIzki+DgAB8CJEQDv9-gQBtjwRJvyL-hnJNZOR6IwqePTC0onBXcxSTGTMAUJMY5mAA-LES6oKuEDrp0OjGK+oGLiua58J0dJOK40AeF4MA+H47KjsAr7vJ8mCeN4virFwpgoF4SDHFEsRAW+wxJKSqQFnwvS5M6BR0cwcFmGBSFQShcBgrs76RAkMFwD0aTcZkvH0SMYxsXAIqzFSZhMZK0pbIgcoKgpfDKaM35fGSzyvMR5kWepNogr+OEAUxZwCaYoiuii0LDGpjzkn8AIcSC4neTCJyiO5SL4Ie+A9sShIJSSak-IFWkEa+xJEuMZIUn4vDUbRFBoQYA5leow7uHygrCtMmkLrpmyynswVFO5QkQchMBnNqcC6vqhrGn1pqvBapJPC8bwfLZEwOSw7meRckI+ScKUBZSwQbMASZwHipJ0lac1MQ6wWfiOTHvIkC7esOfpwAGXBBn1SChjA4aRppMbZu5iZICmfhmOmmbZnmwVFkgpblkglbyjWx31sZ8DNswbZwB2zDdrt+JAA
import _extends from 'babel-runtime/helpers/extends';
import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
import React from 'react';
import PropTypes from 'prop-types';
import EventListener from 'react-event-listener';
import debounce from 'lodash/debounce';
import wrapDisplayName from 'recompose/wrapDisplayName';
import hoistNonReactStatics from 'hoist-non-react-statics';
import withTheme from '../styles/withTheme';
import { keys as breakpointKeys } from '../styles/createBreakpoints';
/**
* By default, returns true if screen width is the same or greater than the given breakpoint.
*
* @param screenWidth
* @param breakpoint
* @param inclusive - defaults to true
*/
export const isWidthUp = (breakpoint, screenWidth, inclusive = true) => {
// By default, returns true if screen width is the same or greater than the given breakpoint.
export const isWidthUp = (breakpoint, width, inclusive = true) => {
if (inclusive) {
return breakpointKeys.indexOf(breakpoint) <= breakpointKeys.indexOf(screenWidth);
return breakpointKeys.indexOf(breakpoint) <= breakpointKeys.indexOf(width);
}
return breakpointKeys.indexOf(breakpoint) < breakpointKeys.indexOf(screenWidth);
return breakpointKeys.indexOf(breakpoint) < breakpointKeys.indexOf(width);
};
/**
* By default, returns true if screen width is the same or less than the given breakpoint.
*
* @param screenWidth
* @param breakpoint
* @param inclusive - defaults to true
*/
export const isWidthDown = (breakpoint, screenWidth, inclusive = true) => {
// By default, returns true if screen width is the same or less than the given breakpoint.
export const isWidthDown = (breakpoint, width, inclusive = true) => {
if (inclusive) {
return breakpointKeys.indexOf(screenWidth) <= breakpointKeys.indexOf(breakpoint);
return breakpointKeys.indexOf(width) <= breakpointKeys.indexOf(breakpoint);
}
return breakpointKeys.indexOf(screenWidth) < breakpointKeys.indexOf(breakpoint);
return breakpointKeys.indexOf(width) < breakpointKeys.indexOf(breakpoint);
};
// optional props introduced by this HOC
const withWidth = (
// eslint-disable-line prettier/prettier
options = {}) => Component => {
const withWidth = (options = {}) => Component => {
const {
resizeInterval = 166 // Corresponds to 10 frames at 60 Hz.
resizeInterval = 166, // Corresponds to 10 frames at 60 Hz.
withTheme: withThemeOption = false
} = options;
// `theme` is injected below by withTheme
class Width extends React.Component {
class WithWidth extends React.Component {
constructor(...args) {
var _temp;
@@ -73,37 +51,35 @@ options = {}) => Component => {
}
updateWidth(innerWidth) {
if (this.props.theme) {
const breakpoints = this.props.theme.breakpoints;
let width = null;
const breakpoints = this.props.theme.breakpoints;
let width = null;
/**
* Start with the slowest value as low end devices often have a small screen.
*
* innerWidth |0 xs sm md lg xl
* |-------|-------|-------|-------|-------|------>
* width | xs | xs | sm | md | lg | xl
*/
let index = 1;
while (width === null && index < breakpointKeys.length) {
const currentWidth = breakpointKeys[index];
/**
* Start with the slowest value as low end devices often have a small screen.
*
* innerWidth |xs sm md lg xl
* |-------|-------|-------|-------|------>
* width | xs | sm | md | lg | xl
*/
let index = 1;
while (width === null && index < breakpointKeys.length) {
const currentWidth = breakpointKeys[index];
// @media are inclusive, so reproduce the behavior here.
if (innerWidth < breakpoints.values[currentWidth]) {
width = breakpointKeys[index - 1];
break;
}
index += 1;
// @media are inclusive, so reproduce the behavior here.
if (innerWidth < breakpoints.values[currentWidth]) {
width = breakpointKeys[index - 1];
break;
}
width = width || 'xl';
index += 1;
}
if (width !== this.state.width) {
this.setState({
width
});
}
width = width || 'xl';
if (width !== this.state.width) {
this.setState({
width
});
}
}
@@ -114,6 +90,11 @@ options = {}) => Component => {
const props = _extends({
width: width || this.state.width || initialWidth
}, other);
const more = {};
if (withThemeOption) {
more.theme = theme;
}
// When rendering the component on the server,
// we have no idea about the client browser screen width.
@@ -128,16 +109,39 @@ options = {}) => Component => {
return React.createElement(
EventListener,
{ target: 'window', onResize: this.handleResize },
React.createElement(Component, props)
React.createElement(Component, _extends({}, more, props))
);
}
}
WithWidth.propTypes = process.env.NODE_ENV !== "production" ? {
/**
* As `window.innerWidth` is unavailable on the server,
* we default to rendering an empty componenent during the first mount.
* In some situation you might want to use an heristic to approximate
* the screen width of the client browser screen width.
*
* For instance, you could be using the user-agent or the client-hints.
* http://caniuse.com/#search=client%20hint
*/
initialWidth: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
/**
* @ignore
*/
theme: PropTypes.object.isRequired,
/**
* Bypass the width calculation logic.
*/
width: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl'])
} : {};
if (process.env.NODE_ENV !== 'production') {
Width.displayName = wrapDisplayName(Component, 'withWidth');
WithWidth.displayName = wrapDisplayName(Component, 'WithWidth');
}
return withTheme()(Width);
hoistNonReactStatics(WithWidth, Component);
return withTheme()(WithWidth);
};
export default withWidth;