Move general components to typescript

This commit is contained in:
Mitchell McCaffrey 2021-07-09 16:58:32 +10:00
parent ecfab87aa0
commit f6d695a48a
20 changed files with 221 additions and 140 deletions

View File

@ -105,6 +105,7 @@
"@types/react-dom": "^17.0.5",
"@types/react-modal": "^3.12.0",
"@types/react-router-dom": "^5.1.7",
"@types/react-select": "^4.0.17",
"@types/shortid": "^0.0.29",
"@types/simple-peer": "^9.6.3",
"@types/uuid": "^8.3.1",

View File

@ -3,7 +3,13 @@ import { Box, Flex, Text, IconButton, Divider } from "theme-ui";
import ExpandMoreIcon from "../icons/ExpandMoreIcon";
function Accordion({ heading, children, defaultOpen }) {
type AccordianProps = {
heading: string;
children: React.ReactNode;
defaultOpen: boolean;
};
function Accordion({ heading, children, defaultOpen }: AccordianProps) {
const [open, setOpen] = useState(defaultOpen);
return (

View File

@ -1,7 +1,16 @@
import React from "react";
import { Divider } from "theme-ui";
import { Divider, DividerProps } from "theme-ui";
function StyledDivider({ vertical, color, fill }) {
type StyledDividerProps = {
vertical: boolean;
fill: boolean;
} & DividerProps;
function StyledDivider({
vertical,
color,
fill,
...props
}: StyledDividerProps) {
return (
<Divider
my={vertical ? 0 : 2}
@ -13,6 +22,7 @@ function StyledDivider({ vertical, color, fill }) {
borderRadius: "2px",
opacity: 0.5,
}}
{...props}
/>
);
}

View File

@ -1,4 +1,3 @@
import React from "react";
import { Flex } from "theme-ui";
import Link from "./Link";

View File

@ -1,4 +1,3 @@
import React from "react";
import { Group, Rect } from "react-konva";
import useImage from "use-image";
@ -16,7 +15,7 @@ import squarePatternLight from "../images/SquarePatternLight.png";
import hexPatternDark from "../images/HexPatternDark.png";
import hexPatternLight from "../images/HexPatternLight.png";
function Grid({ stroke }) {
function Grid({ stroke }: { stroke: "black" | "white" }) {
const grid = useGrid();
const gridPixelSize = useGridPixelSize();
const gridOffset = useGridOffset();
@ -45,7 +44,7 @@ function Grid({ stroke }) {
const negativeGridOffset = Vector2.multiply(gridOffset, -1);
let patternProps = {};
let patternProps: Record<any, any> = {};
if (grid.type === "square") {
// Square grid pattern is 150 DPI
const scale = gridCellPixelSize.width / 300;

View File

@ -1,8 +1,7 @@
import React from "react";
import { Link as ThemeLink } from "theme-ui";
import { Link as ThemeLink, LinkProps } from "theme-ui";
import { HashLink as RouterLink } from "react-router-hash-link";
function Link({ to, ...rest }) {
function Link({ to, ...rest }: { to: string } & LinkProps) {
return (
<RouterLink to={to}>
<ThemeLink as="span" {...rest} />

View File

@ -1,9 +1,14 @@
import React, { useEffect, useRef } from "react";
import { Progress } from "theme-ui";
function LoadingBar({ isLoading, loadingProgressRef }) {
const requestRef = useRef();
const progressBarRef = useRef();
type LoadingBarProps = {
isLoading: boolean;
loadingProgressRef: React.MutableRefObject<number>;
};
function LoadingBar({ isLoading, loadingProgressRef }: LoadingBarProps) {
const requestRef = useRef<number>();
const progressBarRef = useRef<HTMLProgressElement>(null);
// Use an animation frame to update the progress bar
// This bypasses react allowing the animation to be smooth
@ -21,7 +26,9 @@ function LoadingBar({ isLoading, loadingProgressRef }) {
requestRef.current = requestAnimationFrame(animate);
return () => {
cancelAnimationFrame(requestRef.current);
if (requestRef.current !== undefined) {
cancelAnimationFrame(requestRef.current);
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoading]);

View File

@ -1,24 +1,26 @@
import React from "react";
import {
Text,
TextProps,
Image as UIImage,
ImageProps,
Link as UILink,
Message,
Embed,
} from "theme-ui";
import ReactMarkdown from "react-markdown";
function Paragraph(props) {
function Paragraph(props: TextProps) {
return <Text as="p" my={2} variant="body2" {...props} />;
}
function Heading({ level, ...props }) {
function Heading({ level, ...props }: { level: number } & TextProps) {
const fontSize = level === 1 ? 5 : level === 2 ? 3 : 1;
return (
<Text
mt={2}
mb={1}
as={`h${level}`}
as={`h${level}` as React.ElementType}
sx={{ fontSize }}
variant="heading"
{...props}
@ -26,11 +28,11 @@ function Heading({ level, ...props }) {
);
}
function Image(props) {
function Image(props: ImageProps) {
if (props.alt === "embed:") {
return <Embed as="span" sx={{ display: "block" }} src={props.src} my={2} />;
}
if (props.src.endsWith(".mp4")) {
if (props.src?.endsWith(".mp4")) {
return (
<video
style={{ width: "100%", margin: "8px 0" }}
@ -39,7 +41,7 @@ function Image(props) {
playsInline
loop
controls
{...props}
src={props.src}
/>
);
}
@ -47,11 +49,17 @@ function Image(props) {
return <UIImage mt={2} sx={{ borderRadius: "4px" }} {...props} />;
}
function ListItem(props) {
function ListItem(props: TextProps) {
return <Text as="li" variant="body2" my={1} {...props} />;
}
function Code({ children, value }) {
function Code({
children,
value,
}: {
value: string;
children: React.ReactNode;
}) {
let variant = "";
if (value.startsWith("Warning:")) {
variant = "warning";
@ -71,7 +79,7 @@ function Code({ children, value }) {
);
}
function Table({ children }) {
function Table({ children }: { children: React.ReactNode }) {
return (
<Text
as="table"
@ -83,7 +91,7 @@ function Table({ children }) {
);
}
function TableHead(props) {
function TableHead(props: TextProps) {
return (
<Text
as="thead"
@ -94,7 +102,7 @@ function TableHead(props) {
);
}
function TableBody(props) {
function TableBody(props: TextProps) {
return (
<Text
as="tbody"
@ -105,7 +113,7 @@ function TableBody(props) {
);
}
function TableRow({ children }) {
function TableRow({ children }: { children: React.ReactNode }) {
return (
<Text
as="tr"
@ -119,7 +127,7 @@ function TableRow({ children }) {
);
}
function TableCell({ children }) {
function TableCell({ children }: { children: React.ReactNode }) {
return (
<Text as="td" p={2}>
{children}
@ -127,11 +135,17 @@ function TableCell({ children }) {
);
}
function Link({ href, children }) {
function Link({ href, children }: { href: string; children: React.ReactNode }) {
return <UILink href={href}>{children}</UILink>;
}
function Markdown({ source, assets }) {
function Markdown({
source,
assets,
}: {
source: string;
assets: Record<string, string>;
}) {
const renderers = {
paragraph: Paragraph,
heading: Heading,

View File

@ -1,7 +1,17 @@
import React from "react";
import { IconButton } from "theme-ui";
import { IconButton, IconButtonProps } from "theme-ui";
function RadioIconButton({ title, onClick, isSelected, disabled, children }) {
type RadioButttonProps = {
isSelected: boolean;
} & IconButtonProps;
function RadioIconButton({
title,
onClick,
isSelected,
disabled,
children,
...props
}: RadioButttonProps) {
return (
<IconButton
aria-label={title}
@ -9,6 +19,7 @@ function RadioIconButton({ title, onClick, isSelected, disabled, children }) {
onClick={onClick}
sx={{ color: isSelected ? "primary" : "text" }}
disabled={disabled}
{...props}
>
{children}
</IconButton>

View File

@ -1,76 +0,0 @@
import React from "react";
import ReactSelect from "react-select";
import Creatable from "react-select/creatable";
import { useThemeUI } from "theme-ui";
function Select({ creatable, ...props }) {
const { theme } = useThemeUI();
const Component = creatable ? Creatable : ReactSelect;
return (
<Component
styles={{
menu: (provided, state) => ({
...provided,
backgroundColor: theme.colors.background,
color: theme.colors.text,
borderRadius: "4px",
borderColor: theme.colors.gray,
borderStyle: "solid",
borderWidth: "1px",
fontFamily: theme.fonts.body2,
opacity: state.isDisabled ? 0.5 : 1,
}),
control: (provided, state) => ({
...provided,
backgroundColor: "transparent",
color: theme.colors.text,
borderColor: theme.colors.text,
opacity: state.isDisabled ? 0.5 : 1,
}),
singleValue: (provided) => ({
...provided,
color: theme.colors.text,
fontFamily: theme.fonts.body2,
}),
option: (provided, state) => ({
...provided,
color: theme.colors.text,
opacity: state.isDisabled ? 0.5 : 1,
}),
dropdownIndicator: (provided, state) => ({
...provided,
color: theme.colors.text,
":hover": {
color: state.isDisabled
? theme.colors.disabled
: theme.colors.primary,
},
}),
input: (provided, state) => ({
...provided,
color: theme.colors.text,
opacity: state.isDisabled ? 0.5 : 1,
}),
container: (provided) => ({
...provided,
margin: "4px 0",
}),
}}
theme={(t) => ({
...t,
colors: {
...t.colors,
primary: theme.colors.primary,
primary50: theme.colors.secondary,
primary25: theme.colors.highlight,
},
})}
captureMenuScroll={false}
{...props}
/>
);
}
export default Select;

79
src/components/Select.tsx Normal file
View File

@ -0,0 +1,79 @@
import ReactSelect, { Props } from "react-select";
import Creatable from "react-select/creatable";
import { useThemeUI } from "theme-ui";
type SelectProps = {
creatable: boolean;
} & Props;
function Select({ creatable, ...props }: SelectProps) {
const { theme } = useThemeUI();
const Component = creatable ? Creatable : (ReactSelect as any);
return (
<Component
styles={{
menu: (provided: any, state: any) => ({
...provided,
backgroundColor: theme.colors?.background,
color: theme.colors?.text,
borderRadius: "4px",
borderColor: theme.colors?.gray,
borderStyle: "solid",
borderWidth: "1px",
fontFamily: (theme.fonts as any)?.body2,
opacity: state.isDisabled ? 0.5 : 1,
}),
control: (provided: any, state: any) => ({
...provided,
backgroundColor: "transparent",
color: theme.colors?.text,
borderColor: theme.colors?.text,
opacity: state.isDisabled ? 0.5 : 1,
}),
singleValue: (provided: any) => ({
...provided,
color: theme.colors?.text,
fontFamily: (theme.fonts as any).body2,
}),
option: (provided: any, state: any) => ({
...provided,
color: theme.colors?.text,
opacity: state.isDisabled ? 0.5 : 1,
}),
dropdownIndicator: (provided: any, state: any) => ({
...provided,
color: theme.colors?.text,
":hover": {
color: state.isDisabled
? theme.colors?.disabled
: theme.colors?.primary,
},
}),
input: (provided: any, state: any) => ({
...provided,
color: theme.colors?.text,
opacity: state.isDisabled ? 0.5 : 1,
}),
container: (provided: any) => ({
...provided,
margin: "4px 0",
}),
}}
theme={(t: any) => ({
...t,
colors: {
...t.colors,
primary: theme.colors?.primary,
primary50: theme.colors?.secondary,
primary25: theme.colors?.highlight,
},
})}
captureMenuScroll={false}
{...props}
/>
);
}
export default Select;

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import { useState } from "react";
import { IconButton } from "theme-ui";
import SettingsIcon from "../icons/SettingsIcon";

View File

@ -2,15 +2,21 @@ import { useState } from "react";
import { Box, Slider as ThemeSlider, SliderProps } from "theme-ui";
type SliderModalProps = SliderProps & {
min: number,
max: number,
value: number,
ml: any,
mr: any,
labelFunc: any
}
min: number;
max: number;
value: number;
labelFunc: (value: number) => string;
};
function Slider({ min, max, value, ml, mr, labelFunc, ...rest }: SliderModalProps ) {
function Slider({
min,
max,
value,
ml,
mr,
labelFunc,
...rest
}: SliderModalProps) {
const percentValue = ((value - min) * 100) / (max - min);
const [labelVisible, setLabelVisible] = useState<boolean>(false);

View File

@ -1,4 +1,3 @@
import React from "react";
import { Box } from "theme-ui";
import "./Spinner.css";

View File

@ -1,8 +0,0 @@
import TextareaAutosize from "react-textarea-autosize";
import "./TextareaAutoSize.css";
function StyledTextareaAutoSize(props) {
return <TextareaAutosize className="textarea-auto-size" {...props} />;
}
export default StyledTextareaAutoSize;

View File

@ -0,0 +1,10 @@
import TextareaAutosize, {
TextareaAutosizeProps,
} from "react-textarea-autosize";
import "./TextareaAutoSize.css";
function StyledTextareaAutoSize(props: TextareaAutosizeProps) {
return <TextareaAutosize className="textarea-auto-size" {...props} />;
}
export default StyledTextareaAutoSize;

View File

@ -2,7 +2,7 @@ import React from "react";
import { Box, Text } from "theme-ui";
import { ToastProvider as DefaultToastProvider } from "react-toast-notifications";
function CustomToast({ children }) {
function CustomToast({ children }: { children?: React.ReactNode }) {
return (
<Box
m={2}
@ -17,7 +17,7 @@ function CustomToast({ children }) {
);
}
export function ToastProvider({ children }) {
export function ToastProvider({ children }: { children?: React.ReactNode }) {
return (
<DefaultToastProvider
components={{ Toast: CustomToast }}

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react";
import { useState, useEffect } from "react";
import { Text } from "theme-ui";
import LoadingOverlay from "./LoadingOverlay";
@ -21,7 +21,7 @@ const facts = [
];
function UpgradingLoadingOverlay() {
const [subText, setSubText] = useState();
const [subText, setSubText] = useState<string>();
useEffect(() => {
let index = 0;
@ -33,7 +33,7 @@ function UpgradingLoadingOverlay() {
}
// Show first fact after 10 seconds then every 20 seconds after that
let interval;
let interval: NodeJS.Timeout;
let timeout = setTimeout(() => {
updateFact();
interval = setInterval(() => {

17
src/global.d.ts vendored
View File

@ -1,8 +1,9 @@
declare module 'pepjs';
declare module 'socket.io-msgpack-parser';
declare module 'fake-indexeddb';
declare module 'fake-indexeddb/lib/FDBKeyRange';
declare module '*.glb';
declare module '*.png';
declare module '*.mp4';
declare module '*.bin';
declare module "pepjs";
declare module "socket.io-msgpack-parser";
declare module "fake-indexeddb";
declare module "fake-indexeddb/lib/FDBKeyRange";
declare module "*.glb";
declare module "*.png";
declare module "*.mp4";
declare module "*.bin";
declare module "react-router-hash-link";

View File

@ -3056,6 +3056,13 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
"@types/react-dom@*":
version "17.0.9"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.9.tgz#441a981da9d7be117042e1a6fd3dac4b30f55add"
integrity sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==
dependencies:
"@types/react" "*"
"@types/react-dom@^17.0.5":
version "17.0.5"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.5.tgz#df44eed5b8d9e0b13bb0cd38e0ea6572a1231227"
@ -3087,6 +3094,23 @@
"@types/history" "*"
"@types/react" "*"
"@types/react-select@^4.0.17":
version "4.0.17"
resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-4.0.17.tgz#2e5ab4042c09c988bfc2711550329b0c3c9f8513"
integrity sha512-ZK5wcBhJaqC8ntQl0CJvK2KXNNsk1k5flM7jO+vNPPlceRzdJQazA6zTtQUyNr6exp5yrAiwiudtYxgGlgGHLg==
dependencies:
"@emotion/serialize" "^1.0.0"
"@types/react" "*"
"@types/react-dom" "*"
"@types/react-transition-group" "*"
"@types/react-transition-group@*":
version "4.4.2"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.2.tgz#38890fd9db68bf1f2252b99a942998dc7877c5b3"
integrity sha512-KibDWL6nshuOJ0fu8ll7QnV/LVTo3PzQ9aCPnRUYPfX7eZohHwLIdNHj7pftanREzHNP4/nJa8oeM73uSiavMQ==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^17.0.6":
version "17.0.6"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.6.tgz#0ec564566302c562bf497d73219797a5e0297013"