Skip to content

Commit

Permalink
Merge pull request #1488 from outoftime/resizable-flex
Browse files Browse the repository at this point in the history
Reusable resizable flex HOC
  • Loading branch information
outoftime committed Jul 17, 2018
2 parents 13e5298 + a589c7a commit ad7b14c
Show file tree
Hide file tree
Showing 24 changed files with 497 additions and 442 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@
"remark-react-lowlight": "^0.7.0",
"reselect": "^3.0.1",
"scriptjs": "^2.5.8",
"shallowequal": "^1.0.2",
"slowparse": "^1.1.4",
"strip-markdown": "^3.0.0",
"stylelint": "^9.2.0",
Expand All @@ -241,6 +242,7 @@
"analyze-bundle": "gulp js --production && source-map-explorer ./dist/application.js"
},
"devDependencies": {
"almost-equal": "^1.1.0",
"babel-cli": "^6.23.0",
"babel-core": "^6.14.0",
"babel-eslint": "^8.0.1",
Expand Down
9 changes: 5 additions & 4 deletions src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import {
import {
focusLine,
editorFocusedRequestedLine,
dragRowDivider,
dragColumnDivider,
startDragColumnDivider,
stopDragColumnDivider,
notificationTriggered,
Expand Down Expand Up @@ -66,6 +64,10 @@ import {
evaluateConsoleEntry,
} from './console';

import {
updateResizableFlex,
} from './resizableFlex';

export {
clearConsoleEntries,
consoleValueProduced,
Expand All @@ -85,8 +87,6 @@ export {
toggleComponent,
focusLine,
editorFocusedRequestedLine,
dragRowDivider,
dragColumnDivider,
startDragColumnDivider,
stopDragColumnDivider,
notificationTriggered,
Expand All @@ -113,4 +113,5 @@ export {
showSaveIndicator,
hideSaveIndicator,
linkGithubIdentity,
updateResizableFlex,
};
6 changes: 6 additions & 0 deletions src/actions/resizableFlex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {createAction} from 'redux-actions';

export const updateResizableFlex = createAction(
'UPDATE_RESIZABLE_FLEX',
(name, updates) => ({name, updates}),
);
8 changes: 0 additions & 8 deletions src/actions/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ export const editorFocusedRequestedLine = createAction(
'EDITOR_FOCUSED_REQUESTED_LINE',
);

export const dragRowDivider = createAction(
'DRAG_ROW_DIVIDER',
);

export const dragColumnDivider = createAction(
'DRAG_COLUMN_DIVIDER',
);

export const startDragColumnDivider = createAction(
'START_DRAG_COLUMN_DIVIDER',
);
Expand Down
12 changes: 7 additions & 5 deletions src/components/EditorContainer.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import prefixAll from 'inline-style-prefixer/static';
import PropTypes from 'prop-types';
import React from 'react';
import React, {forwardRef} from 'react';
import {t} from 'i18next';

function EditorContainer({children, language, source, style, onHide, onRef}) {
const EditorContainer = forwardRef((
{children, language, source, style, onHide},
ref,
) => {
let helpText;

if (source === '') {
Expand All @@ -17,7 +20,7 @@ function EditorContainer({children, language, source, style, onHide, onRef}) {
return (
<div
className="editors__editor-container"
ref={onRef}
ref={ref}
style={prefixAll(style)}
>
<div
Expand All @@ -32,15 +35,14 @@ function EditorContainer({children, language, source, style, onHide, onRef}) {
{children}
</div>
);
}
});

EditorContainer.propTypes = {
children: PropTypes.node.isRequired,
language: PropTypes.string.isRequired,
source: PropTypes.string.isRequired,
style: PropTypes.object.isRequired,
onHide: PropTypes.func.isRequired,
onRef: PropTypes.func.isRequired,
};

export default EditorContainer;
224 changes: 98 additions & 126 deletions src/components/EditorsColumn.jsx
Original file line number Diff line number Diff line change
@@ -1,168 +1,140 @@
import {DraggableCore} from 'react-draggable';
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import prefixAll from 'inline-style-prefixer/static';
import {t} from 'i18next';
import {DraggableCore} from 'react-draggable';
import bindAll from 'lodash-es/bindAll';
import isEmpty from 'lodash-es/isEmpty';
import includes from 'lodash-es/includes';
import map from 'lodash-es/map';
import partial from 'lodash-es/partial';
import partition from 'lodash-es/partition';

import {getNodeHeights} from '../util/resize';

import EditorContainer from './EditorContainer';
import Editor from './Editor';

export default class EditorsColumn extends React.Component {
constructor(props) {
super(props);
this.dividerRefs = [null, null];
this.editorRefs = [null, null, null];
bindAll(
this,
'_storeDividerRef',
'_storeEditorRef',
'_handleEditorDividerDrag',
);
}

_storeEditorRef(index, editor) {
this.editorRefs[index] = editor;
}

_storeDividerRef(index, divider) {
this.dividerRefs[index] = divider;
}

_handleEditorDividerDrag(index, _, {deltaY, lastY, y}) {
this.props.onDividerDrag({
index,
dividerHeights: getNodeHeights(this.dividerRefs),
editorHeights: getNodeHeights(this.editorRefs),
deltaY,
lastY,
y,
});
}
export default function EditorsColumn({
currentProject,
errors,
resizableFlexGrow,
resizableFlexRefs,
isTextSizeLarge,
requestedFocusedLine,
onComponentHide,
onComponentUnhide,
onEditorInput,
onRef,
onRequestedLineFocused,
onResizableFlexDividerDrag,
style,
}) {
const [hiddenLanguages, visibleLanguages] = partition(
map(
['html', 'css', 'javascript'],
(language, index) => ({language, index}),
),
({language}) => includes(
currentProject.hiddenUIComponents,
`editor.${language}`,
),
);

render() {
const {
currentProject,
editorsFlex,
errors,
isTextSizeLarge,
requestedFocusedLine,
onComponentHide,
onEditorInput,
onRef,
onRequestedLineFocused,
style,
} = this.props;
const children = [];

const children = [];
const [hiddenLanguages, visibleLanguages] = partition(
['html', 'css', 'javascript'],
language => includes(
currentProject.hiddenUIComponents,
`editor.${language}`,
),
);
visibleLanguages.forEach((language, index) => {
children.push(
<EditorContainer
key={language}
visibleLanguages.forEach(({language, index}) => {
children.push(
<EditorContainer
key={language}
language={language}
ref={resizableFlexRefs[index]}
source={currentProject.sources[language]}
style={{flexGrow: resizableFlexGrow.get(index)}}
onHide={partial(
onComponentHide,
currentProject.projectKey,
`editor.${language}`,
)}
>
<Editor
errors={errors[language].items}
language={language}
percentageOfHeight={1 / visibleLanguages.length}
projectKey={currentProject.projectKey}
requestedFocusedLine={requestedFocusedLine}
source={currentProject.sources[language]}
style={{flex: editorsFlex[index]}}
onHide={partial(
onComponentHide,
textSizeIsLarge={isTextSizeLarge}
onInput={partial(
onEditorInput,
currentProject.projectKey,
`editor.${language}`,
language,
)}
onRef={partial(this._storeEditorRef, index)}
onRequestedLineFocused={onRequestedLineFocused}
/>
</EditorContainer>,
);
if (index < visibleLanguages.length - 1) {
children.push(
<DraggableCore
key={`divider:${language}`}
onDrag={partial(onResizableFlexDividerDrag, index)}
>
<Editor
errors={errors[language].items}
language={language}
percentageOfHeight={1 / visibleLanguages.length}
projectKey={currentProject.projectKey}
requestedFocusedLine={requestedFocusedLine}
source={currentProject.sources[language]}
textSizeIsLarge={isTextSizeLarge}
onInput={partial(
onEditorInput,
currentProject.projectKey,
language,
)}
onRequestedLineFocused={onRequestedLineFocused}
/>
</EditorContainer>,
<div className="editors__row-divider" />
</DraggableCore>,
);
if (index < visibleLanguages.length - 1) {
children.push(
<DraggableCore
key={`divider:${language}`}
onDrag={partial(this._handleEditorDividerDrag, index)}
>
<div
className="editors__row-divider"
ref={partial(this._storeDividerRef, index)}
/>
</DraggableCore>,
);
}
});

hiddenLanguages.forEach((language) => {
children.push((
<div
className="editors__collapsed-editor"
key={language}
onClick={partial(
this.props.onComponentUnhide,
currentProject.projectKey,
`editor.${language}`,
)}
>
<div className="label editors__label editors__label_collapsed">
{t(`languages.${language}`)}
{' '}
<span className="u__icon">&#xf077;</span>
</div>
</div>
));
});

if (isEmpty(children)) {
return null;
}
});

return (
hiddenLanguages.forEach(({language}) => {
children.push((
<div
className="environment__column"
ref={onRef}
style={prefixAll(style)}
className="editors__collapsed-editor"
key={language}
onClick={partial(
onComponentUnhide,
currentProject.projectKey,
`editor.${language}`,
)}
>
<div className="environment__column-contents editors">{children}</div>
<div className="label editors__label editors__label_collapsed">
{t(`languages.${language}`)}
{' '}
<span className="u__icon">&#xf077;</span>
</div>
</div>
);
));
});

if (isEmpty(children)) {
return null;
}

return (
<div
className="environment__column"
ref={onRef}
style={prefixAll(style)}
>
<div className="environment__column-contents editors">
{children}
</div>
</div>
);
}

EditorsColumn.propTypes = {
currentProject: PropTypes.object.isRequired,
editorsFlex: PropTypes.array.isRequired,
errors: PropTypes.object.isRequired,
isTextSizeLarge: PropTypes.bool.isRequired,
requestedFocusedLine: PropTypes.object,
resizableFlexGrow: ImmutablePropTypes.list.isRequired,
resizableFlexRefs: PropTypes.array.isRequired,
style: PropTypes.object.isRequired,
onComponentHide: PropTypes.func.isRequired,
onComponentUnhide: PropTypes.func.isRequired,
onDividerDrag: PropTypes.func.isRequired,
onEditorInput: PropTypes.func.isRequired,
onRef: PropTypes.func.isRequired,
onRequestedLineFocused: PropTypes.func.isRequired,
onResizableFlexDividerDrag: PropTypes.func.isRequired,
};

EditorsColumn.defaultProps = {
Expand Down

0 comments on commit ad7b14c

Please sign in to comment.