mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-04 11:43:02 +00:00
87 lines
2.4 KiB
Plaintext
87 lines
2.4 KiB
Plaintext
/* @flow */
|
|
|
|
import React, { type Element as ReactElement, Fragment } from 'react';
|
|
import type { Options } from './../options';
|
|
import {
|
|
createStringTreeNode,
|
|
createNumberTreeNode,
|
|
createReactElementTreeNode,
|
|
createReactFragmentTreeNode,
|
|
} from './../tree';
|
|
import type { TreeNode } from './../tree';
|
|
|
|
const supportFragment = Boolean(Fragment);
|
|
|
|
const getReactElementDisplayName = (element: ReactElement<*>): string =>
|
|
element.type.displayName ||
|
|
element.type.name || // function name
|
|
(typeof element.type === 'function' // function without a name, you should provide one
|
|
? 'No Display Name'
|
|
: element.type);
|
|
|
|
const noChildren = (propsValue, propName) => propName !== 'children';
|
|
|
|
const onlyMeaningfulChildren = (children): boolean =>
|
|
children !== true &&
|
|
children !== false &&
|
|
children !== null &&
|
|
children !== '';
|
|
|
|
const filterProps = (originalProps: {}, cb: (any, string) => boolean) => {
|
|
const filteredProps = {};
|
|
|
|
Object.keys(originalProps)
|
|
.filter(key => cb(originalProps[key], key))
|
|
.forEach(key => (filteredProps[key] = originalProps[key]));
|
|
|
|
return filteredProps;
|
|
};
|
|
|
|
const parseReactElement = (
|
|
element: ReactElement<*> | string | number,
|
|
options: Options
|
|
): TreeNode => {
|
|
const { displayName: displayNameFn = getReactElementDisplayName } = options;
|
|
|
|
if (typeof element === 'string') {
|
|
return createStringTreeNode(element);
|
|
} else if (typeof element === 'number') {
|
|
return createNumberTreeNode(element);
|
|
} else if (!React.isValidElement(element)) {
|
|
throw new Error(
|
|
`react-element-to-jsx-string: Expected a React.Element, got \`${typeof element}\``
|
|
);
|
|
}
|
|
|
|
const displayName = displayNameFn(element);
|
|
|
|
const props = filterProps(element.props, noChildren);
|
|
if (element.ref !== null) {
|
|
props.ref = element.ref;
|
|
}
|
|
|
|
const key = element.key;
|
|
if (typeof key === 'string' && key.search(/^\./)) {
|
|
// React automatically add key=".X" when there are some children
|
|
props.key = key;
|
|
}
|
|
|
|
const defaultProps = filterProps(element.type.defaultProps || {}, noChildren);
|
|
const childrens = React.Children.toArray(element.props.children)
|
|
.filter(onlyMeaningfulChildren)
|
|
.map(child => parseReactElement(child, options));
|
|
|
|
if (supportFragment && element.type === Fragment) {
|
|
return createReactFragmentTreeNode(key, childrens);
|
|
}
|
|
|
|
return createReactElementTreeNode(
|
|
displayName,
|
|
props,
|
|
defaultProps,
|
|
childrens
|
|
);
|
|
};
|
|
|
|
export default parseReactElement;
|