Files
freeCodeCamp/common/app/Panes/Panes.jsx
Berkeley Martinez dced96da8e feat: react challenges (#16099)
* chore(packages): Update redux utils

* feat(Panes): Invert control of panes map creation

* feat(Modern): Add view

* feat(Panes): Decouple panes from Challenges

* fix(Challenges): Decouple challenge views from panes map

* fix(Challenge/views): PanesMap => mapStateToPanesMap

This clarifies what these functions are doing

* fix(Challenges): Add view type

* fix(Panes): Remove unneeded panes container

* feat(Panes): Invert control of pane content render

This decouples the Panes from the content they render, allowing for
greater flexibility.

* feat(Modern): Add side panel

This is common between modern and classic

* feat(seed): Array to string file content

* fix(files): Modern files should be polyvinyls

* feat(Modern): Create editors per file

* fix(seed/React): Incorrect keyfile name

* feat(Modern): Highligh jsx correctly

This adds highlighting for jsx. Unfortunately, this disables linting for
non-javascript files as jshint will only work for those

* feat(rechallenge): Add jsx ext to babel transformer

* feat(seed): Normalize challenge files head/tail/content

* refactor(rechallenge/build): Rename function

* fix(code-storage): Pull in files from localStorage

* feat(Modern/React): Add Enzyme to test runner

This enables testing of React challenges

* feat(Modern): Add submission type

* refactor(Panes): Rename panes map update action
2017-11-29 17:44:51 -06:00

116 lines
2.5 KiB
JavaScript

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import {
panesSelector,
panesByNameSelector,
panesMounted,
heightSelector,
widthSelector
} from './redux';
import Pane from './Pane.jsx';
import Divider from './Divider.jsx';
const mapStateToProps = createSelector(
panesSelector,
panesByNameSelector,
heightSelector,
widthSelector,
(panes, panesByName, height) => {
let lastDividerPosition = 0;
return {
panes: panes
.map(({ name }) => panesByName[name])
.filter(({ isHidden })=> !isHidden)
.map((pane, index, { length: numOfPanes }) => {
const dividerLeft = pane.dividerLeft || 0;
const left = lastDividerPosition;
lastDividerPosition = dividerLeft;
return {
...pane,
left: index === 0 ? 0 : left,
right: index + 1 === numOfPanes ? 0 : 100 - dividerLeft
};
}, {}),
height
};
}
);
const mapDispatchToProps = { panesMounted };
const propTypes = {
height: PropTypes.number.isRequired,
panes: PropTypes.array,
panesMounted: PropTypes.func.isRequired,
render: PropTypes.func.isRequired
};
export class Panes extends PureComponent {
componentDidMount() {
this.props.panesMounted();
}
renderPanes() {
const {
render,
panes
} = this.props;
return panes.map(({ name, left, right, dividerLeft }) => {
const divider = dividerLeft ?
(
<Divider
key={ name + 'divider' }
left={ dividerLeft }
name={ name }
/>
) :
null;
return [
<Pane
key={ name }
left={ left }
right={ right }
>
{ render(name) }
</Pane>,
divider
];
}).reduce((panes, pane) => panes.concat(pane), [])
.filter(Boolean);
}
render() {
const { height } = this.props;
const outerStyle = {
height,
position: 'relative',
width: '100%'
};
const innerStyle = {
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0
};
return (
<div style={outerStyle}>
<div style={innerStyle}>
{ this.renderPanes() }
</div>
</div>
);
}
}
Panes.displayName = 'Panes';
Panes.propTypes = propTypes;
export default connect(
mapStateToProps,
mapDispatchToProps
)(Panes);