1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2025-06-30 22:46:39 -04:00

update component prop types to use JSX.IntrinsicElements

This commit is contained in:
2022-02-09 09:37:20 -05:00
parent f205a14bdc
commit 885f97fa64
40 changed files with 280 additions and 275 deletions

View File

@ -1,11 +1,10 @@
import classNames from "classnames";
import type { HTMLAttributes } from "react";
import styles from "./Blockquote.module.css";
type Props = HTMLAttributes<HTMLElement>;
type BlockquoteProps = JSX.IntrinsicElements["blockquote"];
const Blockquote = ({ className, ...rest }: Props) => (
const Blockquote = ({ className, ...rest }: BlockquoteProps) => (
<blockquote className={classNames(styles.blockquote, className)} {...rest} />
);

View File

@ -1,9 +1,9 @@
import { memo } from "react";
import css from "styled-jsx/css";
import classNames from "classnames";
import Link, { Props as CustomLinkProps } from "../Link/Link";
import Link, { CustomLinkProps } from "../Link/Link";
type Props = CustomLinkProps & {
type ColorfulLinkProps = CustomLinkProps & {
lightColor: string;
darkColor: string;
};
@ -21,7 +21,7 @@ const getLinearGradient = (hex: string, alpha = 0.4) => {
return `linear-gradient(${rgbaString},${rgbaString})`;
};
const ColorfulLink = ({ lightColor, darkColor, className, ...rest }: Props) => {
const ColorfulLink = ({ lightColor, darkColor, className, ...rest }: ColorfulLinkProps) => {
const { className: underlineClassName, styles: underlineStyles } = css.resolve`
a {
color: ${lightColor};

View File

@ -3,17 +3,17 @@ import { useTheme } from "next-themes";
import classNames from "classnames";
import { Giscus } from "@giscus/react";
import { giscusConfig } from "../../lib/config";
import type { PropsWithChildren, HTMLAttributes } from "react";
import type { PropsWithChildren } from "react";
import type { GiscusProps } from "@giscus/react";
import styles from "./Comments.module.css";
type Props = HTMLAttributes<HTMLDivElement> &
type CommentsProps = JSX.IntrinsicElements["div"] &
PropsWithChildren<{
title: string;
}>;
const Comments = ({ title, className, ...rest }: Props) => {
const Comments = ({ title, className, ...rest }: CommentsProps) => {
const { resolvedTheme } = useTheme();
return (

View File

@ -5,16 +5,11 @@ import { Formik, Form, Field } from "formik";
import HCaptcha from "@hcaptcha/react-hcaptcha";
import Link from "../Link/Link";
import { SendIcon, CheckOcticon, XOcticon } from "../Icons";
import type { FormikHelpers } from "formik";
import styles from "./ContactForm.module.css";
const cx = classNames.bind(styles);
type Props = {
className?: string;
};
type Values = {
name: string;
email: string;
@ -22,7 +17,11 @@ type Values = {
"h-captcha-response": string;
};
const ContactForm = ({ className }: Props) => {
type ContactFormProps = {
className?: string;
};
const ContactForm = ({ className }: ContactFormProps) => {
const { resolvedTheme } = useTheme();
// status/feedback:

View File

@ -1,10 +1,11 @@
import classNames from "classnames";
import type { HTMLAttributes } from "react";
import styles from "./Content.module.css";
type Props = HTMLAttributes<HTMLDivElement>;
type ContentProps = JSX.IntrinsicElements["div"];
const Content = ({ className, ...rest }: Props) => <div className={classNames(styles.content, className)} {...rest} />;
const Content = ({ className, ...rest }: ContentProps) => (
<div className={classNames(styles.content, className)} {...rest} />
);
export default Content;

View File

@ -8,14 +8,14 @@ import type { ReactNode, Ref } from "react";
import styles from "./CopyButton.module.css";
const cx = classNames.bind(styles);
type Props = {
type CopyButtonProps = {
source: ReactNode;
timeout?: number;
className?: string;
};
const CopyButton = forwardRef(function CopyButton(
{ source, timeout = 2000, className }: Props,
{ source, timeout = 2000, className }: CopyButtonProps,
ref: Ref<HTMLButtonElement>
) {
const [copied, setCopied] = useState(false);

View File

@ -6,12 +6,12 @@ import type { ImageProps as NextImageProps } from "next/image";
import styles from "./Figure.module.css";
type Props = Omit<NextImageProps, "alt"> &
type FigureProps = Omit<NextImageProps, "alt"> &
PropsWithChildren<{
alt?: string; // becomes optional -- pulled from plaintext-ified caption if missing
}>;
const Figure = ({ children, alt, className, ...imageProps }: Props) => {
const Figure = ({ children, alt, className, ...imageProps }: FigureProps) => {
return (
<figure className={classNames(styles.figure, className)}>
<Image alt={alt || innerText(children)} {...imageProps} />

View File

@ -3,13 +3,12 @@ import Link from "next/link";
import classNames from "classnames";
import { HeartIcon, NextjsLogo } from "../Icons";
import * as config from "../../lib/config";
import type { HTMLAttributes } from "react";
import styles from "./Footer.module.css";
type Props = HTMLAttributes<HTMLDivElement>;
type FooterProps = JSX.IntrinsicElements["div"];
const Footer = ({ className, ...rest }: Props) => (
const Footer = ({ className, ...rest }: FooterProps) => (
<footer className={classNames(styles.footer, className)} {...rest}>
<div className={styles.row}>
<div className={styles.license}>

View File

@ -2,13 +2,12 @@ import { memo } from "react";
import classNames from "classnames";
import Selfie from "../Selfie/Selfie";
import Menu from "../Menu/Menu";
import type { HTMLAttributes } from "react";
import styles from "./Header.module.css";
type Props = HTMLAttributes<HTMLDivElement>;
type HeaderProps = JSX.IntrinsicElements["div"];
const Header = ({ className }: Props) => (
const Header = ({ className }: HeaderProps) => (
<header className={classNames(styles.header, className)}>
<nav className={styles.nav}>
<Selfie className={styles.selfie} />

View File

@ -3,11 +3,11 @@ import type { HTMLAttributes } from "react";
import styles from "./Heading.module.css";
type Props = HTMLAttributes<HTMLHeadingElement> & {
type HeadingProps = HTMLAttributes<HTMLHeadingElement> & {
as: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
};
const Heading = ({ as: Component, id, className, children, ...rest }: Props) => {
const Heading = ({ as: Component, id, className, children, ...rest }: HeadingProps) => {
return (
<Component className={classNames(styles.heading, styles[Component], className)} id={id} {...rest}>
{children}
@ -20,11 +20,11 @@ const Heading = ({ as: Component, id, className, children, ...rest }: Props) =>
);
};
export const H1 = (props: Omit<Props, "as">) => <Heading as="h1" {...props} />;
export const H2 = (props: Omit<Props, "as">) => <Heading as="h2" {...props} />;
export const H3 = (props: Omit<Props, "as">) => <Heading as="h3" {...props} />;
export const H4 = (props: Omit<Props, "as">) => <Heading as="h4" {...props} />;
export const H5 = (props: Omit<Props, "as">) => <Heading as="h5" {...props} />;
export const H6 = (props: Omit<Props, "as">) => <Heading as="h6" {...props} />;
export const H1 = (props: Omit<HeadingProps, "as">) => <Heading as="h1" {...props} />;
export const H2 = (props: Omit<HeadingProps, "as">) => <Heading as="h2" {...props} />;
export const H3 = (props: Omit<HeadingProps, "as">) => <Heading as="h3" {...props} />;
export const H4 = (props: Omit<HeadingProps, "as">) => <Heading as="h4" {...props} />;
export const H5 = (props: Omit<HeadingProps, "as">) => <Heading as="h5" {...props} />;
export const H6 = (props: Omit<HeadingProps, "as">) => <Heading as="h6" {...props} />;
export default Heading;

View File

@ -2,12 +2,12 @@ import useSWR from "swr";
import Loading from "../Loading/Loading";
import { fetcher } from "../../lib/fetcher";
type Props = {
type HitCounterProps = {
slug: string;
className?: string;
};
const HitCounter = ({ slug, className }: Props) => {
const HitCounter = ({ slug, className }: HitCounterProps) => {
// start fetching repos from API immediately
const { data, error } = useSWR(`/api/hits/?slug=${encodeURIComponent(slug)}`, fetcher, {
// avoid double (or more) counting views

View File

@ -1,10 +1,11 @@
import classNames from "classnames";
import type { HTMLAttributes } from "react";
import styles from "./HorizontalRule.module.css";
type Props = HTMLAttributes<HTMLHRElement>;
type HorizontalRuleProps = JSX.IntrinsicElements["hr"];
const HorizontalRule = ({ className, ...rest }: Props) => <hr className={classNames(styles.hr, className)} {...rest} />;
const HorizontalRule = ({ className, ...rest }: HorizontalRuleProps) => (
<hr className={classNames(styles.hr, className)} {...rest} />
);
export default HorizontalRule;

View File

@ -1,9 +1,8 @@
import classNames from "classnames";
import { HTMLAttributes } from "react";
import styles from "./IFrame.module.css";
type Props = HTMLAttributes<HTMLIFrameElement> & {
type IFrameProps = JSX.IntrinsicElements["iframe"] & {
src: string;
height: number;
width?: number; // defaults to 100%
@ -11,7 +10,7 @@ type Props = HTMLAttributes<HTMLIFrameElement> & {
noScroll?: boolean;
};
const IFrame = ({ src, title, height, width, allowScripts, noScroll, className, ...rest }: Props) => (
const IFrame = ({ src, title, height, width, allowScripts, noScroll, className, ...rest }: IFrameProps) => (
<iframe
className={classNames(styles.frame, className)}
src={src}

View File

@ -5,16 +5,16 @@ import classNames from "classnames";
import Header from "../Header/Header";
import Footer from "../Footer/Footer";
import themes, { toCSS } from "../../lib/themes";
import type { PropsWithChildren, HTMLAttributes } from "react";
import type { PropsWithChildren } from "react";
import styles from "./Layout.module.css";
type Props = HTMLAttributes<HTMLDivElement> &
type LayoutProps = JSX.IntrinsicElements["div"] &
PropsWithChildren<{
noContainer?: boolean; // pass true to disable default `<main>` container styles with padding, etc.
}>;
const Layout = ({ noContainer, className, children, ...rest }: Props) => {
const Layout = ({ noContainer, className, children, ...rest }: LayoutProps) => {
const { resolvedTheme } = useTheme();
return (

View File

@ -1,13 +1,13 @@
import NextLink from "next/link";
import classNames from "classnames";
import isAbsoluteUrl from "is-absolute-url";
import type { AnchorHTMLAttributes, PropsWithChildren } from "react";
import type { LinkProps } from "next/link";
import type { PropsWithChildren } from "react";
import type { LinkProps as NextLinkProps } from "next/link";
import styles from "./Link.module.css";
export type Props = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href"> &
LinkProps &
export type CustomLinkProps = Omit<JSX.IntrinsicElements["a"], "href"> &
NextLinkProps &
PropsWithChildren<{
forceNewWindow?: boolean;
}>;
@ -21,7 +21,7 @@ const CustomLink = ({
forceNewWindow,
className,
...rest
}: Props) => {
}: CustomLinkProps) => {
// this component auto-detects whether or not we should use a normal HTML anchor externally or next/link internally,
// can be overridden with `forceNewWindow={true}`.
if (forceNewWindow || isAbsoluteUrl(href.toString())) {

View File

@ -1,16 +1,15 @@
import classNames from "classnames";
import type { HTMLAttributes } from "react";
import styles from "./List.module.css";
export const UnorderedList = ({ className, ...rest }: HTMLAttributes<HTMLUListElement>) => (
export const UnorderedList = ({ className, ...rest }: JSX.IntrinsicElements["ul"]) => (
<ul className={classNames(styles.unordered, className)} {...rest} />
);
export const OrderedList = ({ className, ...rest }: HTMLAttributes<HTMLOListElement>) => (
export const OrderedList = ({ className, ...rest }: JSX.IntrinsicElements["ol"]) => (
<ol className={classNames(styles.ordered, className)} {...rest} />
);
// TODO: this is based on good faith that the children are all `<li>`s...
export const ListItem = ({ className, ...rest }: HTMLAttributes<HTMLLIElement>) => (
export const ListItem = ({ className, ...rest }: JSX.IntrinsicElements["li"]) => (
<li className={classNames(styles.item, className)} {...rest} />
);

View File

@ -3,14 +3,14 @@ import classNames from "classnames";
import styles from "./Loading.module.css";
type Props = {
type LoadingProps = {
width: number; // of entire container, in pixels
boxes?: number; // total number of boxes (default: 3)
timing?: number; // staggered timing between each box's pulse, in seconds (default: 0.1s)
className?: string;
};
const Loading = ({ width, boxes = 3, timing = 0.1, className }: Props) => {
const Loading = ({ width, boxes = 3, timing = 0.1, className }: LoadingProps) => {
// each box is just an empty div
const divs = [];

View File

@ -7,7 +7,7 @@ import { HomeIcon, NotesIcon, ProjectsIcon, ContactIcon } from "../Icons";
import styles from "./Menu.module.css";
type Props = {
type MenuProps = {
className?: string;
};
@ -34,7 +34,7 @@ const links = [
},
];
const Menu = ({ className }: Props) => {
const Menu = ({ className }: MenuProps) => {
const router = useRouter();
return (

View File

@ -5,7 +5,7 @@ import { ReactNode } from "react";
import styles from "./MenuLink.module.css";
const cx = classNames.bind(styles);
type Props = {
type MenuLinkProps = {
href: string;
icon: ReactNode;
text: string;
@ -13,7 +13,7 @@ type Props = {
className?: string;
};
const MenuLink = ({ href, icon, text, current, className }: Props) => (
const MenuLink = ({ href, icon, text, current, className }: MenuLinkProps) => (
<Link href={href} prefetch={false}>
<a className={cx(styles.link, { current: !!current }, className)}>
{icon} <span className={styles.label}>{text}</span>

View File

@ -8,9 +8,9 @@ import type { NoteMetaType } from "../../types";
import styles from "./NoteMeta.module.css";
import Link from "next/link";
type Props = Pick<NoteMetaType, "slug" | "date" | "title" | "tags">;
type NoteMetaProps = Pick<NoteMetaType, "slug" | "date" | "title" | "tags">;
const NoteMeta = ({ slug, date, title, tags = [] }: Props) => (
const NoteMeta = ({ slug, date, title, tags = [] }: NoteMetaProps) => (
<div className={styles.meta}>
<div className={styles.meta_item}>
<Link

View File

@ -1,13 +1,12 @@
import Link from "next/link";
import classNames from "classnames";
import type { HTMLAttributes } from "react";
import type { NoteMetaType } from "../../types";
import styles from "./NoteTitle.module.css";
type Props = Pick<NoteMetaType, "slug" | "htmlTitle"> & HTMLAttributes<HTMLAnchorElement>;
type NoteTitleProps = Pick<NoteMetaType, "slug" | "htmlTitle"> & JSX.IntrinsicElements["a"];
const NoteTitle = ({ slug, htmlTitle, className, ...rest }: Props) => (
const NoteTitle = ({ slug, htmlTitle, className, ...rest }: NoteTitleProps) => (
<h1 className={classNames(styles.title, className)}>
<Link
href={{

View File

@ -4,7 +4,11 @@ import type { NoteMetaType } from "../../types";
import styles from "./NotesList.module.css";
const NotesList = ({ notesByYear }) => {
type NotesListProps = {
notesByYear: Record<string, NoteMetaType[]>;
};
const NotesList = ({ notesByYear }: NotesListProps) => {
const sections = [];
Object.entries(notesByYear).forEach(([year, notes]: [string, NoteMetaType[]]) => {

View File

@ -1,14 +1,13 @@
import classNames from "classnames";
import { OctocatOcticon } from "../Icons";
import type { HTMLAttributes } from "react";
import styles from "./OctocatLink.module.css";
type Props = HTMLAttributes<HTMLAnchorElement> & {
type OctocatLinkProps = JSX.IntrinsicElements["a"] & {
repo: string;
};
const OctocatLink = ({ repo, className, ...rest }: Props) => (
const OctocatLink = ({ repo, className, ...rest }: OctocatLinkProps) => (
<a className={styles.link} href={`https://github.com/${repo}`} target="_blank" rel="noopener noreferrer" {...rest}>
<OctocatOcticon fill="currentColor" className={classNames(styles.icon, className)} />
</a>

View File

@ -2,13 +2,12 @@ import { useRouter } from "next/router";
import Link from "next/link";
import classNames from "classnames";
import { baseUrl } from "../../lib/config";
import type { HTMLAttributes } from "react";
import styles from "./PageTitle.module.css";
type Props = HTMLAttributes<HTMLHeadingElement>;
type PageTitleProps = JSX.IntrinsicElements["h1"];
const PageTitle = ({ className, children, ...rest }: Props) => {
const PageTitle = ({ className, children, ...rest }: PageTitleProps) => {
const router = useRouter();
const canonical = `${baseUrl}${router.pathname}/`;

View File

@ -6,11 +6,20 @@ import type { RepoType } from "../../types";
import styles from "./RepositoryCard.module.css";
type Props = RepoType & {
type RepositoryCardProps = RepoType & {
className?: string;
};
const RepositoryCard = ({ name, url, description, language, stars, forks, updatedAt, className }: Props) => (
const RepositoryCard = ({
name,
url,
description,
language,
stars,
forks,
updatedAt,
className,
}: RepositoryCardProps) => (
<div className={classNames(styles.card, className)}>
<Link className={styles.name} href={url}>
{name}

View File

@ -7,11 +7,11 @@ import styles from "./Selfie.module.css";
import selfieJpg from "../../public/static/images/selfie.jpg";
type Props = {
type SelfieProps = {
className?: string;
};
const Selfie = ({ className }: Props) => (
const Selfie = ({ className }: SelfieProps) => (
<Link href="/">
<a className={classNames(styles.link, className)}>
<div className={styles.selfie}>

View File

@ -1,13 +1,13 @@
import { forwardRef } from "react";
import classNames from "classnames";
import type { Ref, HTMLAttributes } from "react";
import type { Ref } from "react";
import styles from "./Terminal.module.css";
type Props = HTMLAttributes<HTMLDivElement>;
type TerminalProps = JSX.IntrinsicElements["div"];
// a DOS-style terminal box with dynamic text
const Terminal = forwardRef(function Terminal({ className, ...rest }: Props, ref: Ref<HTMLSpanElement>) {
const Terminal = forwardRef(function Terminal({ className, ...rest }: TerminalProps, ref: Ref<HTMLSpanElement>) {
return (
<div className={classNames("monospace", className, styles.terminal)} {...rest}>
<span ref={ref} /> <span className={styles.blink} />

View File

@ -4,11 +4,11 @@ import { SunIcon, MoonIcon } from "../Icons";
import styles from "./ThemeToggle.module.css";
type Props = {
type ThemeToggleProps = {
className?: string;
};
const ThemeToggle = ({ className }: Props) => {
const ThemeToggle = ({ className }: ThemeToggleProps) => {
const [mounted, setMounted] = useState(false);
const { resolvedTheme, setTheme } = useTheme();

View File

@ -1,12 +1,12 @@
import Tweet from "react-tweet-embed";
type Props = {
type TweetEmbedProps = {
id: string;
options?: object;
className?: string;
};
const TweetEmbed = ({ id, className, options }: Props) => (
const TweetEmbed = ({ id, className, options }: TweetEmbedProps) => (
<Tweet
className={className}
id={id}

View File

@ -5,11 +5,11 @@ import Terminal from "../Terminal/Terminal";
import styles from "./VNC.module.css";
type Props = {
type VNCProps = {
server: string;
};
const VNC = ({ server }: Props) => {
const VNC = ({ server }: VNCProps) => {
const router = useRouter();
// we definitely do NOT want this page to connect more than once!

View File

@ -4,7 +4,7 @@ import type { FilePlayerProps } from "react-player/file";
import styles from "./Video.module.css";
type Props = Partial<FilePlayerProps> & {
type VideoProps = Partial<FilePlayerProps> & {
webm?: string;
mp4?: string;
thumbnail?: string;
@ -13,7 +13,7 @@ type Props = Partial<FilePlayerProps> & {
className?: string;
};
const Video = ({ webm, mp4, thumbnail, subs, autoplay, className, ...rest }: Props) => {
const Video = ({ webm, mp4, thumbnail, subs, autoplay, className, ...rest }: VideoProps) => {
const url = [
webm && {
src: webm,

View File

@ -1,17 +1,17 @@
import { useEffect, useRef } from "react";
import classNames from "classnames/bind";
import type { PropsWithChildren, HTMLAttributes } from "react";
import type { PropsWithChildren } from "react";
import styles from "./Wallpaper.module.css";
const cx = classNames.bind(styles);
type Props = HTMLAttributes<HTMLDivElement> &
type WallpaperProps = JSX.IntrinsicElements["div"] &
PropsWithChildren<{
image: string;
tile?: boolean;
}>;
const Wallpaper = ({ image, tile, className, ...rest }: Props) => {
const Wallpaper = ({ image, tile, className, ...rest }: WallpaperProps) => {
const bgRef = useRef<HTMLDivElement>(null);
useEffect(() => {

View File

@ -4,12 +4,12 @@ import type { YouTubePlayerProps } from "react-player/youtube";
import styles from "./YouTubeEmbed.module.css";
type Props = Partial<YouTubePlayerProps> & {
type YouTubeEmbedProps = Partial<YouTubePlayerProps> & {
id: string;
className?: string;
};
const YouTubeEmbed = ({ id, className, ...rest }: Props) => (
const YouTubeEmbed = ({ id, className, ...rest }: YouTubeEmbedProps) => (
<div className={classNames(styles.wrapper, className)}>
<ReactPlayer
width="100%"