mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-03-26 08:01:08 -04:00
chore: TS migrate MultifileEditor (#45857)
This commit is contained in:
1
client/src/declarations.d.ts
vendored
1
client/src/declarations.d.ts
vendored
@@ -1,4 +1,5 @@
|
||||
declare module '@freecodecamp/react-bootstrap';
|
||||
declare module '@freecodecamp/loop-protect';
|
||||
declare module '@freecodecamp/strip-comments';
|
||||
declare module '@types/react-redux';
|
||||
declare module '@types/validator';
|
||||
|
||||
@@ -346,7 +346,7 @@ export type CompletedChallenge = {
|
||||
};
|
||||
|
||||
export type Ext = 'js' | 'html' | 'css' | 'jsx';
|
||||
export type FileKey = 'scriptjs' | 'indexhtml' | 'stylescss';
|
||||
export type FileKey = 'scriptjs' | 'indexhtml' | 'stylescss' | 'indexjsx';
|
||||
|
||||
export type ChallengeMeta = {
|
||||
block: string;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useRef } from 'react';
|
||||
import React, { MutableRefObject, RefObject, useRef } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { ReflexContainer, ReflexElement, ReflexSplitter } from 'react-reflex';
|
||||
import { createSelector } from 'reselect';
|
||||
import { editor } from 'monaco-editor';
|
||||
import { isDonationModalOpenSelector, userSelector } from '../../../redux';
|
||||
import {
|
||||
canFocusEditorSelector,
|
||||
@@ -11,46 +11,58 @@ import {
|
||||
} from '../redux';
|
||||
import { getTargetEditor } from '../utils/get-target-editor';
|
||||
import './editor.css';
|
||||
import {
|
||||
ChallengeFile,
|
||||
Dimensions,
|
||||
Ext,
|
||||
FileKey,
|
||||
ResizeProps,
|
||||
Test
|
||||
} from '../../../redux/prop-types';
|
||||
import { Themes } from '../../../components/settings/theme';
|
||||
import Editor from './editor';
|
||||
|
||||
const propTypes = {
|
||||
canFocus: PropTypes.bool,
|
||||
// TODO: use shape
|
||||
challengeFiles: PropTypes.array,
|
||||
containerRef: PropTypes.any.isRequired,
|
||||
contents: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
dimensions: PropTypes.object,
|
||||
editorRef: PropTypes.any.isRequired,
|
||||
ext: PropTypes.string,
|
||||
fileKey: PropTypes.string,
|
||||
initialEditorContent: PropTypes.string,
|
||||
initialExt: PropTypes.string,
|
||||
initialTests: PropTypes.array,
|
||||
output: PropTypes.arrayOf(PropTypes.string),
|
||||
resizeProps: PropTypes.shape({
|
||||
onStopResize: PropTypes.func,
|
||||
onResize: PropTypes.func
|
||||
}),
|
||||
theme: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
showProjectPreview: PropTypes.bool,
|
||||
usesMultifileEditor: PropTypes.bool,
|
||||
visibleEditors: PropTypes.shape({
|
||||
scriptjs: PropTypes.bool,
|
||||
indexjsx: PropTypes.bool,
|
||||
stylescss: PropTypes.bool,
|
||||
indexhtml: PropTypes.bool
|
||||
})
|
||||
type VisibleEditors = {
|
||||
[key: string]: boolean;
|
||||
};
|
||||
|
||||
interface MultifileEditorProps {
|
||||
canFocus?: boolean;
|
||||
challengeFiles: ChallengeFile[];
|
||||
containerRef: RefObject<HTMLElement>;
|
||||
contents?: string;
|
||||
description: string;
|
||||
dimensions?: Dimensions;
|
||||
editorRef: MutableRefObject<editor.IStandaloneCodeEditor>;
|
||||
ext?: Ext;
|
||||
fileKey?: string;
|
||||
initialEditorContent?: string;
|
||||
initialExt?: string;
|
||||
initialTests: Test[];
|
||||
output?: string[];
|
||||
resizeProps: ResizeProps;
|
||||
title: string;
|
||||
showProjectPreview: boolean;
|
||||
usesMultifileEditor: boolean;
|
||||
visibleEditors: {
|
||||
indexhtml?: boolean;
|
||||
indexjsx?: boolean;
|
||||
stylescss?: boolean;
|
||||
scriptjs?: boolean;
|
||||
};
|
||||
}
|
||||
const mapStateToProps = createSelector(
|
||||
visibleEditorsSelector,
|
||||
canFocusEditorSelector,
|
||||
consoleOutputSelector,
|
||||
isDonationModalOpenSelector,
|
||||
userSelector,
|
||||
(visibleEditors, canFocus, output, open, { theme = 'default' }) => ({
|
||||
(
|
||||
visibleEditors: VisibleEditors,
|
||||
canFocus: boolean,
|
||||
output: string[],
|
||||
open,
|
||||
{ theme = Themes.Default }: { theme: Themes }
|
||||
) => ({
|
||||
visibleEditors,
|
||||
canFocus: open ? false : canFocus,
|
||||
output,
|
||||
@@ -58,21 +70,19 @@ const mapStateToProps = createSelector(
|
||||
})
|
||||
);
|
||||
|
||||
const MultifileEditor = props => {
|
||||
const MultifileEditor = (props: MultifileEditorProps) => {
|
||||
const {
|
||||
challengeFiles,
|
||||
containerRef,
|
||||
description,
|
||||
editorRef,
|
||||
initialTests,
|
||||
theme,
|
||||
resizeProps,
|
||||
title,
|
||||
visibleEditors: { stylescss, indexhtml, scriptjs, indexjsx },
|
||||
usesMultifileEditor,
|
||||
showProjectPreview
|
||||
} = props;
|
||||
const editorTheme = theme === 'night' ? 'vs-dark-custom' : 'vs-custom';
|
||||
// TODO: the tabs mess up the rendering (scroll doesn't work properly and
|
||||
// the in-editor description)
|
||||
|
||||
@@ -94,7 +104,7 @@ const MultifileEditor = props => {
|
||||
if (stylescss) editorKeys.push('stylescss');
|
||||
if (scriptjs) editorKeys.push('scriptjs');
|
||||
|
||||
const editorAndSplitterKeys = editorKeys.reduce((acc, key) => {
|
||||
const editorAndSplitterKeys = editorKeys.reduce((acc: string[] | [], key) => {
|
||||
if (acc.length === 0) {
|
||||
return [key];
|
||||
} else {
|
||||
@@ -124,12 +134,16 @@ const MultifileEditor = props => {
|
||||
canFocusOnMountRef={canFocusOnMountRef}
|
||||
challengeFiles={challengeFiles}
|
||||
containerRef={containerRef}
|
||||
description={targetEditor === key ? description : null}
|
||||
description={targetEditor === key ? description : ''}
|
||||
editorRef={editorRef}
|
||||
fileKey={key}
|
||||
fileKey={key as FileKey}
|
||||
initialTests={initialTests}
|
||||
resizeProps={resizeProps}
|
||||
theme={editorTheme}
|
||||
contents={props.contents ?? ''}
|
||||
dimensions={props.dimensions ?? { height: 0, width: 0 }}
|
||||
ext={props.ext ?? 'html'}
|
||||
initialEditorContent={props.initialEditorContent ?? ''}
|
||||
initialExt={props.initialExt ?? ''}
|
||||
title={title}
|
||||
usesMultifileEditor={usesMultifileEditor}
|
||||
showProjectPreview={showProjectPreview}
|
||||
@@ -145,6 +159,5 @@ const MultifileEditor = props => {
|
||||
};
|
||||
|
||||
MultifileEditor.displayName = 'MultifileEditor';
|
||||
MultifileEditor.propTypes = propTypes;
|
||||
|
||||
export default connect(mapStateToProps)(MultifileEditor);
|
||||
@@ -1,5 +1,5 @@
|
||||
import { graphql } from 'gatsby';
|
||||
import React, { Component } from 'react';
|
||||
import React, { Component, MutableRefObject } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { TFunction, withTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
@@ -8,6 +8,7 @@ import Media from 'react-responsive';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
import { createStructuredSelector } from 'reselect';
|
||||
import store from 'store';
|
||||
import { editor } from 'monaco-editor';
|
||||
import { challengeTypes } from '../../../../utils/challenge-types';
|
||||
import LearnLayout from '../../../components/layouts/learn';
|
||||
|
||||
@@ -51,7 +52,7 @@ import {
|
||||
} from '../redux';
|
||||
import { savedChallengesSelector } from '../../../redux';
|
||||
import { getGuideUrl } from '../utils';
|
||||
import MultifileEditor from './MultifileEditor';
|
||||
import MultifileEditor from './multifile-editor';
|
||||
import DesktopLayout from './desktop-layout';
|
||||
import MobileLayout from './mobile-layout';
|
||||
|
||||
@@ -141,7 +142,7 @@ const BASE_LAYOUT = {
|
||||
class ShowClassic extends Component<ShowClassicProps, ShowClassicState> {
|
||||
static displayName: string;
|
||||
containerRef: React.RefObject<HTMLElement>;
|
||||
editorRef: React.RefObject<HTMLElement>;
|
||||
editorRef: React.RefObject<editor.IStandaloneCodeEditor | HTMLElement>;
|
||||
instructionsPanelRef: React.RefObject<HTMLDivElement>;
|
||||
resizeProps: ResizeProps;
|
||||
|
||||
@@ -385,7 +386,10 @@ class ShowClassic extends Component<ShowClassicProps, ShowClassicState> {
|
||||
challengeFiles={challengeFiles}
|
||||
containerRef={this.containerRef}
|
||||
description={description}
|
||||
editorRef={this.editorRef}
|
||||
// Try to remove unknown
|
||||
editorRef={
|
||||
this.editorRef as MutableRefObject<editor.IStandaloneCodeEditor>
|
||||
}
|
||||
initialTests={tests}
|
||||
resizeProps={this.resizeProps}
|
||||
title={title}
|
||||
@@ -449,7 +453,7 @@ class ShowClassic extends Component<ShowClassicProps, ShowClassicState> {
|
||||
|
||||
return (
|
||||
<Hotkeys
|
||||
editorRef={this.editorRef}
|
||||
editorRef={this.editorRef as React.RefObject<HTMLElement>}
|
||||
executeChallenge={executeChallenge}
|
||||
innerRef={this.containerRef}
|
||||
instructionsPanelRef={this.instructionsPanelRef}
|
||||
|
||||
Reference in New Issue
Block a user