Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate project source to TypeScript #346

Merged
merged 3 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"loose": true
}
],
"@babel/preset-react"
"@babel/preset-typescript",
["@babel/preset-react", { "runtime": "automatic" }]
],
"plugins": [
"add-module-exports",
Expand All @@ -21,4 +22,4 @@
}
]
]
}
}
5 changes: 5 additions & 0 deletions .changeset/ninety-boats-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-live": major
---

Migrated codebase to TypeScript.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
"root": true,
"parser": "@babel/eslint-parser",
"plugins": ["prettier"],
"plugins": ["prettier", "@typescript-eslint"],
"settings": {
"react": {
"version": "detect"
}
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:import/recommended"
],
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/code-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ jobs:
- name: Test
run: yarn run test

- name: Type Check
run: yarn run typecheck

- name: Library Build
run: yarn run build

Expand Down
5 changes: 3 additions & 2 deletions .storybook/.babelrc
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
"@babel/preset-typescript",
["@babel/preset-react", { "runtime": "automatic" }]
],
"plugins": [
"add-module-exports",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-proposal-class-properties"
]
}
}
2 changes: 1 addition & 1 deletion .storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
"stories": [
"../stories/**/*js"
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
"@storybook/addon-controls",
Expand Down
18 changes: 13 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "3.2.0",
"description": "A production-focused playground for live editing React code",
"main": "dist/react-live.cjs.js",
"typings": "./typings/react-live.d.ts",
"types": "dist/index.d.ts",
"jsnext:main": "dist/react-live.es.js",
"module": "dist/react-live.es.js",
"license": "MIT",
Expand All @@ -16,6 +16,7 @@
"prepublishOnly": "npm run build",
"test": "jest",
"test:typings": "typings-tester --dir typings",
"typecheck": "tsc --noEmit",
"lint": "eslint --config .eslintrc \"./src/**/*.js\"",
"install:docs": "yarn --cwd website install",
"start:docs": "yarn --cwd website start",
Expand All @@ -37,17 +38,23 @@
"@babel/plugin-transform-runtime": "^7.15.0",
"@babel/preset-env": "^7.15.0",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.21.0",
"@changesets/cli": "^2.26.1",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^20.0.0",
"@rollup/plugin-node-resolve": "^13.0.4",
"@rollup/plugin-replace": "^3.0.0",
"@rollup/plugin-typescript": "^11.0.0",
"@storybook/addon-controls": "^6.4.13",
"@storybook/builder-webpack5": "^6.5.16",
"@storybook/manager-webpack5": "^6.5.16",
"@storybook/react": "^6.4.13",
"@svitejs/changesets-changelog-github-compact": "^1.1.0",
"@types/react": "^17.0.38",
"@types/prismjs": "^1.26.0",
"@types/react": "^18.0.31",
"@types/styled-components": "^5.1.26",
"@typescript-eslint/eslint-plugin": "^5.57.0",
"@typescript-eslint/parser": "^5.57.0",
"babel-jest": "^27.0.6",
"babel-loader": "^8.2.2",
"babel-plugin-add-module-exports": "^1.0.4",
Expand All @@ -61,15 +68,16 @@
"prettier": "^2.5.1",
"prismjs": "^1.26.0",
"prop-types": "^15.7.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react": "^18.2.0",
"react-docgen-typescript": "^2.2.2",
"react-dom": "^18.2.0",
"react-test-renderer": "^17.0.2",
"rollup": "^2.55.1",
"rollup-plugin-filesize": "^9.1.1",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-visualizer": "^5.5.4",
"styled-components": "^4.0.0-beta.8",
"typescript": "^2.9.2",
"typescript": "^4.9",
"typings-tester": "^0.3.1",
"webpack": "^5.76.3"
},
Expand Down
7 changes: 6 additions & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { babel } from "@rollup/plugin-babel";
import { terser } from "rollup-plugin-terser";
import filesize from "rollup-plugin-filesize";
import { visualizer } from "rollup-plugin-visualizer";
import typescript from "@rollup/plugin-typescript";
Comment on lines 5 to +8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to change this now, but in the future we might look into swapping rollup out for Vite (which uses rollup under the hood), just because the plugin/config is a bit less verbose. Maybe something for "future us".


const plugins = [
nodeResolve({
Expand Down Expand Up @@ -33,13 +34,15 @@ const plugins = [
];

const devPlugins = plugins.concat([
typescript(),
replace({
"process.env.NODE_ENV": JSON.stringify("development"),
preventAssignment: true,
}),
]);

const prodPlugins = plugins.concat([
typescript(),
replace({
"process.env.NODE_ENV": JSON.stringify("production"),
preventAssignment: true,
Expand All @@ -50,19 +53,21 @@ const prodPlugins = plugins.concat([
]);

const base = {
input: "src/index.js",
input: "src/index.ts",
external: [
"react",
"react-dom",
"prop-types",
"prism-react-renderer",
"sucrase",
"react/jsx-runtime",
],
};

const output = {
exports: "named",
globals: {
"react/jsx-runtime": "jsx-runtime",
"prism-react-renderer": "Prism",
react: "React",
sucrase: "Sucrase",
Expand Down
36 changes: 18 additions & 18 deletions src/components/Editor/index.js → src/components/Editor/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
import Highlight, { Prism } from "prism-react-renderer";
import PropTypes from "prop-types";
import React, { useCallback, useEffect, useRef, useState } from "react";
import Highlight, { Language, Prism, PrismTheme } from "prism-react-renderer";
import { CSSProperties, useCallback, useEffect, useRef, useState } from "react";
import { useEditable } from "use-editable";
import { theme as liveTheme } from "../../constants/theme";

const CodeEditor = (props) => {
export type Props = {
className?: string;
code: string;
disabled?: boolean;
language: Language;
prism?: typeof Prism;
style?: CSSProperties;
tabMode?: "focus" | "indentation";
theme?: PrismTheme;
onChange?(value: string): void;
};

const CodeEditor = (props: Props) => {
const editorRef = useRef(null);
const [code, setCode] = useState(props.code || "");

useEffect(() => {
setCode(props.code);
}, [props.code]);

const onEditableChange = useCallback((_code) => {
const onEditableChange = useCallback((_code: string) => {
setCode(_code.slice(0, -1));
}, []);

Expand Down Expand Up @@ -41,6 +52,7 @@ const CodeEditor = (props) => {
getLineProps,
getTokenProps,
style: _style,
/* @ts-ignore — this property exists but the lib's types are incorrect */
theme: _theme,
}) => (
<pre
Expand Down Expand Up @@ -79,20 +91,8 @@ const CodeEditor = (props) => {
);
};

CodeEditor.propTypes = {
className: PropTypes.string,
code: PropTypes.string,
disabled: PropTypes.bool,
language: PropTypes.string,
onChange: PropTypes.func,
prism: PropTypes.object,
style: PropTypes.object,
tabMode: PropTypes.oneOf(["focus", "indentation"]),
theme: PropTypes.object,
};

CodeEditor.defaultProps = {
tabMode: "indentation",
};
} as Pick<Props, "tabMode">;

export default CodeEditor;
5 changes: 0 additions & 5 deletions src/components/Live/LiveContext.js

This file was deleted.

17 changes: 17 additions & 0 deletions src/components/Live/LiveContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Language, PrismTheme } from "prism-react-renderer";
import { ComponentType, createContext } from "react";

type ContextValue = {
error?: string;
element?: ComponentType | null;
code: string;
disabled: boolean;
language: Language;
theme?: PrismTheme;
onError(error: Error): void;
onChange(value: string): void;
}

const LiveContext = createContext<ContextValue>({} as ContextValue);

export default LiveContext;
16 changes: 10 additions & 6 deletions stories/Editor.js → src/components/Live/LiveEditor.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import React from "react";
import Prism from "prismjs";
import { Editor } from "../src/index";
import { Editor } from "../../index";
import type { Story } from "@storybook/react";

export default {
title: "Editor",
component: Editor,
};

const Template = (args) => <Editor {...args} />;
const Template = (args: any) => <Editor {...args} />;

const defaultArgs = {
language: "js",
code: "const x = 'Hello World!';",
};

export const Default = Template.bind({});
export const Default: Story = Template.bind({});
Default.args = defaultArgs;

export const FontFamilyExample = Template.bind({});
export const FontFamilyExample: Story = Template.bind({});
FontFamilyExample.args = {
...defaultArgs,
style: {
Expand All @@ -27,5 +27,9 @@ FontFamilyExample.args = {

// Can't pass Prism as an arg since it is not JSON-serializable
export const PrismFromNpm = () => (
<Editor language="js" prism={Prism} code="const x = 'Hello World!';" />
<Editor
language="javascript"
prism={Prism as any}
code="const x = 'Hello World!';"
/>
);
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useContext } from "react";
import LiveContext from "./LiveContext";
import Editor from "../Editor";
import Editor, { Props as EditorProps } from "../Editor";

export default function LiveEditor(props) {
export default function LiveEditor(props: Partial<EditorProps>) {
const { code, language, theme, disabled, onChange } = useContext(LiveContext);

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useContext } from "react";
import LiveContext from "./LiveContext";

export default function LiveError(props) {
export default function LiveError<T extends Record<string, unknown>>(props: T) {
const { error } = useContext(LiveContext);
return error ? <pre {...props}>{error}</pre> : null;
}
18 changes: 0 additions & 18 deletions src/components/Live/LivePreview.js

This file was deleted.

16 changes: 16 additions & 0 deletions src/components/Live/LivePreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React, { PropsWithChildren, useContext } from "react";
import LiveContext from "./LiveContext";

type Props = {
Component?: React.ComponentType<PropsWithChildren<Record<string, unknown>>>;
};

const fallbackComponent = (
props: PropsWithChildren<Record<string, unknown>>
) => <div {...props} />;

function LivePreview({ Component = fallbackComponent, ...rest }: Props) {
const { element: Element } = useContext(LiveContext);
return <Component {...rest}>{Element ? <Element /> : null}</Component>;
}
export default LivePreview;
Loading