mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2025-09-14 01:55:31 -04:00
formik-powered contact page (#725)
This commit is contained in:
@@ -16,6 +16,10 @@
|
||||
outline: none; // disable browsers' outer border
|
||||
border-color: var(--link);
|
||||
}
|
||||
|
||||
&.missing {
|
||||
border-color: var(--error);
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
@@ -43,7 +47,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.captcha {
|
||||
.hcaptcha {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
@@ -71,13 +75,7 @@
|
||||
}
|
||||
|
||||
.send_icon {
|
||||
height: 1.2em;
|
||||
width: 1.2em;
|
||||
vertical-align: -0.22em;
|
||||
border: 0;
|
||||
display: inline-block;
|
||||
margin-right: 0.4em;
|
||||
cursor: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,3 +91,7 @@
|
||||
.result_error {
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
@@ -1,40 +1,35 @@
|
||||
import { useState } from "react";
|
||||
import { useTheme } from "next-themes";
|
||||
import classNames from "classnames/bind";
|
||||
import { Formik, Form, Field } from "formik";
|
||||
import HCaptcha from "@hcaptcha/react-hcaptcha";
|
||||
import { CheckOcticon, XOcticon } from "../icons/octicons";
|
||||
import isEmailLike from "is-email-like";
|
||||
import { SendIcon } from "../icons";
|
||||
import { CheckOcticon, XOcticon } from "../icons/octicons";
|
||||
|
||||
import type { FormikHelpers } from "formik";
|
||||
|
||||
import styles from "./ContactForm.module.scss";
|
||||
const cx = classNames.bind(styles);
|
||||
|
||||
type Values = {
|
||||
name: string;
|
||||
email: string;
|
||||
message: string;
|
||||
"h-captcha-response": string;
|
||||
};
|
||||
|
||||
const ContactForm = () => {
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
// status/feedback:
|
||||
const [status, setStatus] = useState({ success: false, message: "" });
|
||||
// keep track of fetch:
|
||||
const [sending, setSending] = useState(false);
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
const [success, setSuccess] = useState(null);
|
||||
const [feedback, setFeedback] = useState("");
|
||||
|
||||
const onSubmit = (e) => {
|
||||
// immediately prevent browser from actually navigating to a new page
|
||||
e.preventDefault();
|
||||
|
||||
// begin the process
|
||||
setSending(true);
|
||||
|
||||
// extract data from form fields
|
||||
const formData = {
|
||||
name: e.target.elements.name?.value,
|
||||
email: e.target.elements.email?.value,
|
||||
message: e.target.elements.message?.value,
|
||||
"h-captcha-response": e.target.elements["h-captcha-response"]?.value,
|
||||
};
|
||||
|
||||
// some client-side validation to save requests (these are also checked on the server to be safe)
|
||||
if (!(formData.name && formData.email && formData.message && formData["h-captcha-response"])) {
|
||||
setSending(false);
|
||||
setStatus({ success: false, message: "Please make sure that all fields are filled in." });
|
||||
|
||||
return;
|
||||
}
|
||||
const handleSubmit = (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
|
||||
// once a user attempts a submission, this is true and stays true whether or not the next attempt(s) are successful
|
||||
setSubmitted(true);
|
||||
|
||||
// if we've gotten here then all data is (or should be) valid and ready to post to API
|
||||
fetch("/api/contact/", {
|
||||
@@ -43,101 +38,146 @@ const ContactForm = () => {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify(formData),
|
||||
body: JSON.stringify(values),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
setSending(false);
|
||||
|
||||
if (data.success === true) {
|
||||
// handle successful submission
|
||||
// disable submissions, hide the send button, and let user know we were successful
|
||||
setStatus({ success: true, message: "Thanks! You should hear from me soon." });
|
||||
setSuccess(true);
|
||||
setFeedback("Thanks! You should hear from me soon.");
|
||||
} else {
|
||||
// pass on any error sent by the server
|
||||
// pass on any error sent by the server to the catch block below
|
||||
throw new Error(data.message);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
const message = error instanceof Error ? error.message : "UNKNOWN_EXCEPTION";
|
||||
setSuccess(false);
|
||||
|
||||
setSending(false);
|
||||
|
||||
// give user feedback based on the error message returned
|
||||
if (message === "USER_INVALID_CAPTCHA") {
|
||||
setStatus({
|
||||
success: false,
|
||||
message: "Did you complete the CAPTCHA? (If you're human, that is...)",
|
||||
});
|
||||
} else if (message === "USER_MISSING_DATA") {
|
||||
setStatus({
|
||||
success: false,
|
||||
message: "Please make sure that all fields are filled in.",
|
||||
});
|
||||
if (error.message === "USER_MISSING_DATA") {
|
||||
// this should be validated client-side but it's also checked server-side just in case someone slipped past
|
||||
setFeedback("Please make sure that all fields are properly filled in.");
|
||||
} else if (error.message === "USER_INVALID_CAPTCHA") {
|
||||
// missing/invalid captcha
|
||||
setFeedback("Did you complete the CAPTCHA? (If you're human, that is...)");
|
||||
} else {
|
||||
// something else went wrong, and it's probably my fault...
|
||||
setStatus({ success: false, message: "Internal server error. Try again later?" });
|
||||
setFeedback("Internal server error... Try again later or shoot me an old-fashioned email?");
|
||||
}
|
||||
});
|
||||
})
|
||||
.finally(() => setSubmitting(false));
|
||||
};
|
||||
|
||||
return (
|
||||
<form className={styles.form} onSubmit={onSubmit} action="/api/contact/" method="POST">
|
||||
<input type="text" name="name" placeholder="Name" required disabled={status.success} />
|
||||
<input type="email" name="email" placeholder="Email" required disabled={status.success} />
|
||||
<textarea name="message" placeholder="Write something..." required disabled={status.success} />
|
||||
<Formik
|
||||
onSubmit={handleSubmit}
|
||||
initialValues={{
|
||||
name: "",
|
||||
email: "",
|
||||
message: "",
|
||||
"h-captcha-response": "",
|
||||
}}
|
||||
validate={(values: Values) => {
|
||||
const errors: { name?: boolean; email?: boolean; message?: boolean; "h-captcha-response"?: boolean } = {};
|
||||
|
||||
<div className={styles.markdown_tip}>
|
||||
Basic{" "}
|
||||
<a
|
||||
href="https://commonmark.org/help/"
|
||||
title="Markdown reference sheet"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Markdown syntax
|
||||
</a>{" "}
|
||||
is allowed here, e.g.: <strong>**bold**</strong>, <em>_italics_</em>, [
|
||||
<a href="https://jarv.is" target="_blank" rel="noopener noreferrer">
|
||||
links
|
||||
</a>
|
||||
](https://jarv.is), and <code>`code`</code>.
|
||||
</div>
|
||||
errors.name = !values.name;
|
||||
errors.email = !values.email || !isEmailLike(values.email); // also loosely validate email with regex (not foolproof)
|
||||
errors.message = !values.message;
|
||||
errors["h-captcha-response"] = !values["h-captcha-response"];
|
||||
|
||||
<div className={styles.captcha}>
|
||||
<HCaptcha
|
||||
sitekey={process.env.NEXT_PUBLIC_HCAPTCHA_SITE_KEY}
|
||||
size="normal"
|
||||
theme={resolvedTheme === "dark" ? "dark" : "light"}
|
||||
onVerify={() => true} // this is allegedly optional but a function undefined error is thrown without it
|
||||
/>
|
||||
</div>
|
||||
if (!errors.name && !errors.email && !errors.message && !errors["h-captcha-response"]) {
|
||||
setFeedback("");
|
||||
return null;
|
||||
} else {
|
||||
setSuccess(false);
|
||||
setFeedback("Please make sure that all fields are properly filled in.");
|
||||
}
|
||||
|
||||
<div className={styles.action_row}>
|
||||
<button
|
||||
className={styles.btn_submit}
|
||||
title="Send Message"
|
||||
aria-label="Send Message"
|
||||
disabled={sending}
|
||||
style={{ display: status.success ? "none" : null }}
|
||||
>
|
||||
{sending ? (
|
||||
<span>Sending...</span>
|
||||
) : (
|
||||
<>
|
||||
<SendIcon className={styles.send_icon} /> <span>Send</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
return errors;
|
||||
}}
|
||||
>
|
||||
{({ setFieldValue, isSubmitting, touched, errors }) => (
|
||||
<Form className={styles.form} name="contact">
|
||||
<Field
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="Name"
|
||||
className={cx({ missing: errors.name && touched.name })}
|
||||
disabled={success}
|
||||
/>
|
||||
<Field
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Email"
|
||||
className={cx({ missing: errors.email && touched.email })}
|
||||
disabled={success}
|
||||
/>
|
||||
<Field
|
||||
className={cx({ missing: errors.message && touched.message })}
|
||||
component="textarea"
|
||||
name="message"
|
||||
placeholder="Write something..."
|
||||
disabled={success}
|
||||
/>
|
||||
|
||||
<span
|
||||
className={status.success ? styles.result_success : styles.result_error}
|
||||
style={{ display: !status.message || sending ? "none" : null }}
|
||||
>
|
||||
{status.success ? <CheckOcticon fill="CurrentColor" /> : <XOcticon fill="CurrentColor" />} {status.message}
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
<div className={styles.markdown_tip}>
|
||||
Basic{" "}
|
||||
<a
|
||||
href="https://commonmark.org/help/"
|
||||
title="Markdown reference sheet"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Markdown syntax
|
||||
</a>{" "}
|
||||
is allowed here, e.g.: <strong>**bold**</strong>, <em>_italics_</em>, [
|
||||
<a href="https://jarv.is" target="_blank" rel="noopener noreferrer">
|
||||
links
|
||||
</a>
|
||||
](https://jarv.is), and <code>`code`</code>.
|
||||
</div>
|
||||
|
||||
<div className={styles.hcaptcha}>
|
||||
<HCaptcha
|
||||
sitekey={process.env.NEXT_PUBLIC_HCAPTCHA_SITE_KEY}
|
||||
size="normal"
|
||||
theme={resolvedTheme === "dark" ? "dark" : "light"}
|
||||
onVerify={(token) => setFieldValue("h-captcha-response", token)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.action_row}>
|
||||
<button
|
||||
className={cx({ btn_submit: true, hidden: success })}
|
||||
type="submit"
|
||||
title="Send Message"
|
||||
aria-label="Send Message"
|
||||
onClick={() => setSubmitted(true)}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<span>Sending...</span>
|
||||
) : (
|
||||
<>
|
||||
<SendIcon className={`icon ${styles.send_icon}`} /> <span>Send</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
|
||||
<span
|
||||
className={cx({
|
||||
result_success: success,
|
||||
result_error: !success,
|
||||
hidden: !submitted || !feedback || isSubmitting,
|
||||
})}
|
||||
>
|
||||
{success ? <CheckOcticon fill="CurrentColor" /> : <XOcticon fill="CurrentColor" />} {feedback}
|
||||
</span>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
);
|
||||
};
|
||||
|
||||
|
@@ -33,15 +33,18 @@
|
||||
"@octokit/graphql": "^4.8.0",
|
||||
"@primer/octicons-react": "^16.2.0",
|
||||
"@sentry/node": "^6.16.1",
|
||||
"classnames": "^2.3.1",
|
||||
"colord": "^2.9.2",
|
||||
"copy-to-clipboard": "^3.3.1",
|
||||
"date-fns": "^2.28.0",
|
||||
"fathom-client": "^3.2.0",
|
||||
"faunadb": "^4.4.1",
|
||||
"feed": "^4.2.2",
|
||||
"formik": "^2.2.9",
|
||||
"gray-matter": "^4.0.3",
|
||||
"highlight.js": "^11.4.0",
|
||||
"is-absolute-url": "^4.0.1",
|
||||
"is-email-like": "^2.0.0",
|
||||
"markdown-to-jsx": "^7.1.5",
|
||||
"modern-normalize": "github:sindresorhus/modern-normalize#1fc6b5a86676b7ac8abc62d04d6080f92debc70f",
|
||||
"next": "v12.0.8-canary.18",
|
||||
|
61
yarn.lock
61
yarn.lock
@@ -2038,6 +2038,11 @@ character-reference-invalid@^1.0.0:
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
classnames@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
|
||||
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
|
||||
|
||||
clean-stack@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
|
||||
@@ -2331,6 +2336,11 @@ deep-is@^0.1.3:
|
||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
|
||||
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
|
||||
|
||||
deepmerge@^2.1.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
|
||||
integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==
|
||||
|
||||
deepmerge@^4.0.0, deepmerge@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||
@@ -2421,6 +2431,11 @@ electron-to-chromium@^1.4.17:
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.36.tgz#446c6184dbe5baeb5eae9a875490831e4bc5319a"
|
||||
integrity sha512-MbLlbF39vKrXWlFEFpCgDHwdlz4O3LmHM5W4tiLRHjSmEUXjJjz8sZkMgWgvYxlZw3N1iDTmCEtOkkESb5TMCg==
|
||||
|
||||
email-regex@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/email-regex/-/email-regex-5.0.0.tgz#c8b1f4c7f251929b53586a7a3891da09c8dea26d"
|
||||
integrity sha512-he76Cm8JFxb6OGQHabLBPdsiStgPmJeAEhctmw0uhonUh1pCBsHpI6/rB62s2GNzjBb0YlhIcF/1l9Lp5AfH0Q==
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
||||
@@ -2939,6 +2954,19 @@ formdata-polyfill@^4.0.10:
|
||||
dependencies:
|
||||
fetch-blob "^3.1.2"
|
||||
|
||||
formik@^2.2.9:
|
||||
version "2.2.9"
|
||||
resolved "https://registry.yarnpkg.com/formik/-/formik-2.2.9.tgz#8594ba9c5e2e5cf1f42c5704128e119fc46232d0"
|
||||
integrity sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==
|
||||
dependencies:
|
||||
deepmerge "^2.1.1"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
lodash "^4.17.21"
|
||||
lodash-es "^4.17.21"
|
||||
react-fast-compare "^2.0.1"
|
||||
tiny-warning "^1.0.2"
|
||||
tslib "^1.10.0"
|
||||
|
||||
fraction.js@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.2.tgz#13e420a92422b6cf244dff8690ed89401029fbe8"
|
||||
@@ -3259,6 +3287,13 @@ highlight.js@~11.3.0:
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.3.1.tgz#813078ef3aa519c61700f84fe9047231c5dc3291"
|
||||
integrity sha512-PUhCRnPjLtiLHZAQ5A/Dt5F8cWZeMyj9KRsACsWT+OD6OP0x6dp5OmT5jdx0JgEyPxPZZIPQpRN2TciUT7occw==
|
||||
|
||||
hoist-non-react-statics@^3.3.0:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
dependencies:
|
||||
react-is "^16.7.0"
|
||||
|
||||
hosted-git-info@^2.1.4:
|
||||
version "2.8.9"
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
|
||||
@@ -3438,6 +3473,13 @@ is-decimal@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5"
|
||||
integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==
|
||||
|
||||
is-email-like@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-email-like/-/is-email-like-2.0.0.tgz#8277f1bcd919bb8e9f77ed97077b9c56eac3d0f0"
|
||||
integrity sha512-F5uCGvUAEoGjVBpftCwro4En3eImPvCMG22LTHZNn4GxPX2xsBec69AxI6ryzqNJXbwUvXaiUu6dcpSoylMasA==
|
||||
dependencies:
|
||||
email-regex "^5.0.0"
|
||||
|
||||
is-extendable@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
|
||||
@@ -3785,6 +3827,11 @@ locate-path@^6.0.0:
|
||||
dependencies:
|
||||
p-locate "^5.0.0"
|
||||
|
||||
lodash-es@^4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
|
||||
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
||||
|
||||
lodash.debounce@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
@@ -4568,6 +4615,11 @@ react-dom@^17.0.2:
|
||||
object-assign "^4.1.1"
|
||||
scheduler "^0.20.2"
|
||||
|
||||
react-fast-compare@^2.0.1:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
|
||||
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
|
||||
|
||||
react-fast-compare@^3.0.1:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
|
||||
@@ -4588,7 +4640,7 @@ react-is@17.0.2, react-is@^17.0.2:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||
|
||||
react-is@^16.13.1:
|
||||
react-is@^16.13.1, react-is@^16.7.0:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
@@ -5499,6 +5551,11 @@ through@^2.3.8:
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
|
||||
|
||||
tiny-warning@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
|
||||
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||
@@ -5561,7 +5618,7 @@ tsconfig-paths@^3.12.0, tsconfig-paths@^3.9.0:
|
||||
minimist "^1.2.0"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
tslib@^1.8.1, tslib@^1.9.3:
|
||||
tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.3:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
Reference in New Issue
Block a user