Merge commit 'ba1a17578f91bae58a938936d120883a38ed34e3' into FBRICKS-332

This commit is contained in:
gitstart-formbricks
2023-06-09 16:45:53 +00:00
51 changed files with 1908 additions and 606 deletions

View File

@@ -14,6 +14,7 @@ Fixes # (issue)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] Chore (refactoring code, technical debt, workflow improvements)
- [ ] Enhancement (small improvements)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change adds a new database migration
@@ -37,4 +38,5 @@ Fixes # (issue)
- [ ] Checked for warnings, there are none
- [ ] Removed all `console.logs`
- [ ] Merged the latest changes from main onto my branch with `git pull origin main`
- [ ] My changes don't cause any responsiveness issues
- [ ] Updated the Formbricks Docs if changes were necessary

View File

@@ -48,22 +48,6 @@ export default function TemplateList({ onTemplateClick, activeTemplate }: Templa
))}
</div>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{/* <button
type="button"
onClick={() => {
onTemplateClick(activeTemplate);
setActiveTemplate(activeTemplate);
}}
className={cn(
activeTemplate?.name === customSurvey.name
? "ring-brand border-transparent ring-2"
: "hover:border-brand-dark border-dashed border-slate-300",
"duration-120 group relative rounded-lg border-2 bg-transparent p-8 transition-colors duration-150"
)}>
<PlusCircleIcon className="text-brand-dark h-8 w-8 transition-all duration-150 group-hover:scale-110" />
<h3 className="text-md mb-1 mt-3 text-left font-bold text-slate-700 ">{customSurvey.name}</h3>
<p className="text-left text-xs text-slate-600 ">{customSurvey.description}</p>
</button> */}
{templates
.filter((template) => selectedFilter === ALL_CATEGORY_NAME || template.category === selectedFilter)
.map((template: Template) => (

View File

@@ -28,7 +28,7 @@ import type { Template } from "@formbricks/types/templates";
const thankYouCardDefault = {
enabled: true,
headline: "Thank you!",
subheader: "We appreciate your time and insight.",
subheader: "We appreciate your feedback.",
};
export const customSurvey: Template = {

View File

@@ -260,7 +260,12 @@ export default function Header() {
<Link
href="/blog"
className="text-base font-medium text-slate-400 hover:text-slate-700 dark:hover:text-slate-300">
Blog <p className="bg-brand inline rounded-full px-2 text-xs text-white">1</p>
Blog {/* <p className="bg-brand inline rounded-full px-2 text-xs text-white">1</p> */}
</Link>
<Link
href="/careers"
className="text-base font-medium text-slate-400 hover:text-slate-700 dark:hover:text-slate-300">
Careers <p className="bg-brand inline rounded-full px-2 text-xs text-white">2</p>
</Link>
{/* <Link
@@ -363,6 +368,7 @@ export default function Header() {
<Link href="#pricing">Pricing</Link>
<Link href="/docs">Docs</Link>
<Link href="/blog">Blog</Link>
<Link href="/careers">Careers</Link>
<Button
variant="secondary"
EndIcon={GitHubIcon}

View File

@@ -0,0 +1,46 @@
import Layout from "@/components/shared/Layout";
import HeroTitle from "@/components/shared/HeroTitle";
import Link from "next/link";
const Roles = [
{
name: "Full-Stack Engineer",
description: "Join early and be a part of our journey from start to IPO 🚀",
location: "Worldwide",
workplace: "Remote",
},
{
name: "Junior Full-Stack Engineer",
description: "All you want is write code and learn? You're exactly right!",
location: "Worldwide",
workplace: "Remote",
},
];
export default function CareersPage() {
return (
<Layout
title="Careers"
description="Work with us on helping teams make customer-centric decisions - all privacy-focused.">
<HeroTitle
headingPt1="Help teams make"
headingTeal="customer-centric"
headingPt2="decisions."
subheading="We are hiring! Please see all open roles below:"
/>
<div className="mx-auto w-3/4">
{Roles.map((role) => (
<Link
href="https://formbricks.notion.site/Work-at-Formbricks-6c3ad218b2c7461ca2714ce2101730e4?pvs=4"
target="_blank"
key="role.name">
<div className="mb-6 rounded-lg border border-slate-300 bg-slate-100 p-6 shadow-sm hover:bg-slate-50">
<h4 className="text-xl font-bold text-slate-700">{role.name}</h4>
<p className="text-lg text-slate-500">{role.description}</p>
</div>
</Link>
))}
</div>
</Layout>
);
}

View File

@@ -39,12 +39,6 @@ const OSSFriends = [
"Survey granular user segments at any point in the user journey. Gather up to 6x more insights with targeted micro-surveys. All open-source.",
href: "https://formbricks.com",
},
{
name: "Forward Email",
description:
"Free email forwarding for custom domains. For 6 years and counting, we are the go-to email service for thousands of creators, developers, and businesses.",
href: "https://forwardemail.net",
},
{
name: "GitWonk",
description:

View File

@@ -18,7 +18,6 @@ export default function FormbricksClient({ session }) {
formbricks.init({
environmentId: process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID || "",
apiHost: process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST || "",
logLevel: "debug",
});
formbricks.setUserId(session.user.id);
formbricks.setEmail(session.user.email);

View File

@@ -78,7 +78,12 @@ export default function PreviewSurvey({
frameRef.current = requestAnimationFrame(frame);
} else {
handleStopCountdown();
// close modal
setIsModalOpen(false);
// reopen the modal after 1 second
setTimeout(() => {
setIsModalOpen(true);
setActiveQuestionId(questions[0]?.id || ""); // set first question as active
}, 1500);
}
};
@@ -133,13 +138,13 @@ export default function PreviewSurvey({
case "notEquals":
return answerValue !== logic.value;
case "lessThan":
return answerValue < logic.value;
return logic.value !== undefined && answerValue < logic.value;
case "lessEqual":
return answerValue <= logic.value;
return logic.value !== undefined && answerValue <= logic.value;
case "greaterThan":
return answerValue > logic.value;
return logic.value !== undefined && answerValue > logic.value;
case "greaterEqual":
return answerValue >= logic.value;
return logic.value !== undefined && answerValue >= logic.value;
case "includesAll":
return (
Array.isArray(answerValue) &&

View File

@@ -21,12 +21,14 @@ export default function CTAQuestionForm({
lastQuestion,
}: CTAQuestionFormProps): JSX.Element {
const [firstRender, setFirstRender] = useState(true);
return (
<form>
<div className="mt-3">
<Label htmlFor="headline">Question</Label>
<div className="mt-2">
<Input
autoFocus
id="headline"
name="headline"
value={question.headline}

View File

@@ -292,7 +292,7 @@ export default function LogicEditor({
{localSurvey.questions.map(
(question, idx) =>
idx !== questionIdx && (
<SelectItem key={question.id} value={question.id}>
<SelectItem key={question.id} value={question.id} title={question.headline}>
{idx + 1} - {truncate(question.headline, 14)}
</SelectItem>
)
@@ -317,9 +317,10 @@ export default function LogicEditor({
<div className="mt-2 flex items-center space-x-2">
<Button
id="logicJumps"
className="bg-slate-100 px-6 py-2 hover:bg-slate-50"
className="bg-slate-100 hover:bg-slate-50"
type="button"
name="logicJumps"
size="sm"
variant="secondary"
StartIcon={SplitIcon}
onClick={() => addLogic()}>

View File

@@ -4,6 +4,7 @@ import { Button, Input, Label } from "@formbricks/ui";
import { TrashIcon } from "@heroicons/react/24/solid";
import { createId } from "@paralleldrive/cuid2";
import { cn } from "@formbricks/lib/cn";
import { useEffect, useRef, useState } from "react";
interface OpenQuestionFormProps {
localSurvey: Survey;
@@ -19,6 +20,10 @@ export default function MultipleChoiceMultiForm({
updateQuestion,
lastQuestion,
}: OpenQuestionFormProps): JSX.Element {
const lastChoiceRef = useRef<HTMLInputElement>(null);
const [isNew, setIsNew] = useState(true);
const questionRef = useRef<HTMLInputElement>(null);
const updateChoice = (choiceIdx: number, updatedAttributes: any) => {
const newChoices = !question.choices
? []
@@ -32,6 +37,7 @@ export default function MultipleChoiceMultiForm({
};
const addChoice = () => {
setIsNew(false); // This question is no longer new.
let newChoices = !question.choices ? [] : question.choices;
const otherChoice = newChoices.find((choice) => choice.id === "other");
if (otherChoice) {
@@ -70,12 +76,26 @@ export default function MultipleChoiceMultiForm({
updateQuestion(questionIdx, { choices: newChoices, logic: newLogic });
};
useEffect(() => {
if (lastChoiceRef.current) {
lastChoiceRef.current?.focus();
}
}, [question.choices?.length]);
// This effect will run once on initial render, setting focus to the question input.
useEffect(() => {
if (isNew && questionRef.current) {
questionRef.current.focus();
}
}, [isNew]);
return (
<form>
<div className="mt-3">
<Label htmlFor="headline">Question</Label>
<div className="mt-2">
<Input
ref={questionRef}
id="headline"
name="headline"
value={question.headline}
@@ -103,6 +123,7 @@ export default function MultipleChoiceMultiForm({
question.choices.map((choice, choiceIdx) => (
<div key={choiceIdx} className="inline-flex w-full items-center">
<Input
ref={choiceIdx === question.choices.length - 1 ? lastChoiceRef : null}
id={choice.id}
name={choice.id}
value={choice.label}
@@ -119,7 +140,7 @@ export default function MultipleChoiceMultiForm({
</div>
))}
<div className="flex items-center space-x-2">
<Button variant="secondary" type="button" onClick={() => addChoice()}>
<Button variant="secondary" size="sm" type="button" onClick={() => addChoice()}>
Add Option
</Button>
{question.choices.filter((c) => c.id === "other").length === 0 && (

View File

@@ -4,6 +4,7 @@ import { Button, Input, Label } from "@formbricks/ui";
import { TrashIcon } from "@heroicons/react/24/solid";
import { createId } from "@paralleldrive/cuid2";
import { cn } from "@formbricks/lib/cn";
import { useEffect, useRef, useState } from "react";
interface OpenQuestionFormProps {
localSurvey: Survey;
@@ -19,6 +20,10 @@ export default function MultipleChoiceSingleForm({
updateQuestion,
lastQuestion,
}: OpenQuestionFormProps): JSX.Element {
const lastChoiceRef = useRef<HTMLInputElement>(null);
const [isNew, setIsNew] = useState(true);
const questionRef = useRef<HTMLInputElement>(null);
const updateChoice = (choiceIdx: number, updatedAttributes: any) => {
const newChoices = !question.choices
? []
@@ -32,6 +37,7 @@ export default function MultipleChoiceSingleForm({
};
const addChoice = () => {
setIsNew(false); // This question is no longer new.
let newChoices = !question.choices ? [] : question.choices;
const otherChoice = newChoices.find((choice) => choice.id === "other");
if (otherChoice) {
@@ -70,12 +76,26 @@ export default function MultipleChoiceSingleForm({
updateQuestion(questionIdx, { choices: newChoices, logic: newLogic });
};
useEffect(() => {
if (lastChoiceRef.current) {
lastChoiceRef.current?.focus();
}
}, [question.choices?.length]);
// This effect will run once on initial render, setting focus to the question input.
useEffect(() => {
if (isNew && questionRef.current) {
questionRef.current.focus();
}
}, [isNew]);
return (
<form>
<div className="mt-3">
<Label htmlFor="headline">Question</Label>
<div className="mt-2">
<Input
ref={questionRef}
id="headline"
name="headline"
value={question.headline}
@@ -103,6 +123,7 @@ export default function MultipleChoiceSingleForm({
question.choices.map((choice, choiceIdx) => (
<div key={choiceIdx} className="inline-flex w-full items-center">
<Input
ref={choiceIdx === question.choices.length - 1 ? lastChoiceRef : null}
id={choice.id}
name={choice.id}
value={choice.label}
@@ -119,7 +140,7 @@ export default function MultipleChoiceSingleForm({
</div>
))}
<div className="flex items-center space-x-2">
<Button variant="secondary" type="button" onClick={() => addChoice()}>
<Button variant="secondary" size="sm" type="button" onClick={() => addChoice()}>
Add Option
</Button>
{question.choices.filter((c) => c.id === "other").length === 0 && (

View File

@@ -22,6 +22,7 @@ export default function NPSQuestionForm({
<Label htmlFor="headline">Question</Label>
<div className="mt-2">
<Input
autoFocus
id="headline"
name="headline"
value={question.headline}

View File

@@ -22,6 +22,7 @@ export default function OpenQuestionForm({
<Label htmlFor="headline">Question</Label>
<div className="mt-2">
<Input
autoFocus
id="headline"
name="headline"
value={question.headline}

View File

@@ -24,6 +24,7 @@ export default function RatingQuestionForm({
<Label htmlFor="headline">Question</Label>
<div className="mt-2">
<Input
autoFocus
id="headline"
name="headline"
value={question.headline}

View File

@@ -73,6 +73,12 @@ export default function WhenToSendCard({ environmentId, localSurvey, setLocalSur
setLocalSurvey(updatedSurvey);
};
const handleTriggerDelay = (e: any) => {
let value = parseInt(e.target.value);
const updatedSurvey: Survey = { ...localSurvey, delay: value };
setLocalSurvey(updatedSurvey);
};
useEffect(() => {
if (localSurvey.type === "link") {
setOpen(false);
@@ -199,6 +205,30 @@ export default function WhenToSendCard({ environmentId, localSurvey, setLocalSur
Add condition
</Button>
</div>
{localSurvey.type !== "link" && (
<div className="ml-2 flex items-center space-x-1 px-4 pb-4">
<label
htmlFor="triggerDelay"
className="flex w-full cursor-pointer items-center rounded-lg border bg-slate-50 p-4">
<div className="">
<p className="text-sm font-semibold text-slate-700">
Wait
<Input
type="number"
min="0"
id="triggerDelay"
value={localSurvey.delay.toString()}
onChange={(e) => handleTriggerDelay(e)}
className="ml-2 mr-2 inline w-16 text-center text-sm"
/>
seconds before showing the survey.
</p>
</div>
</label>
</div>
)}
<div className="ml-2 flex items-center space-x-1 p-4">
<Switch id="autoClose" checked={autoClose} onCheckedChange={handleCheckMark} />
<Label htmlFor="autoClose" className="cursor-pointer">

View File

@@ -36,7 +36,7 @@ export default function MultipleChoiceSummary({
const results: ChoiceResult[] = useMemo(() => {
if (!("choices" in questionSummary.question)) return [];
console.log(questionSummary.responses);
// build a dictionary of choices
const resultsDict: { [key: string]: ChoiceResult } = {};
for (const choice of questionSummary.question.choices) {

View File

@@ -20,6 +20,7 @@ import { useSearchParams } from "next/navigation";
import { useEffect, useMemo, useState } from "react";
import toast from "react-hot-toast";
import LinkSurveyModal from "./LinkSurveyModal";
import { timeSinceConditionally } from "@formbricks/lib/time";
export default function SummaryMetadata({ surveyId, environmentId }) {
const { responsesData, isLoadingResponses, isErrorResponses } = useResponses(environmentId, surveyId);
@@ -128,7 +129,9 @@ export default function SummaryMetadata({ surveyId, environmentId }) {
</TooltipProvider>
</div>
<div className="flex flex-col justify-between lg:col-span-1">
<div className=""></div>
<div className="text-right text-xs text-slate-400">
Last updated: {timeSinceConditionally(survey.updatedAt)}
</div>
<div className="flex justify-end gap-x-1.5">
{survey.type === "link" && (
<Button
@@ -143,6 +146,7 @@ export default function SummaryMetadata({ surveyId, environmentId }) {
<SurveyStatusDropdown surveyId={surveyId} environmentId={environmentId} />
) : null}
<Button
variant="darkCTA"
className="h-full w-full px-3 lg:px-6"
href={`/environments/${environmentId}/surveys/${surveyId}/edit`}>
<PencilSquareIcon className="mr-2 h-5 w-5 text-white" />

View File

@@ -14,6 +14,8 @@ import { SparklesIcon } from "@heroicons/react/24/solid";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { customSurvey, templates } from "./templates";
import { SplitIcon } from "lucide-react";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@formbricks/ui";
type TemplateList = {
environmentId: string;
@@ -35,12 +37,6 @@ export default function TemplateList({ environmentId, onTemplateClick }: Templat
const [categories, setCategories] = useState<Array<string>>([]);
/* useEffect(() => {
if (product && templates?.length) {
setActiveTemplate(customSurvey);
}
}, [product]); */
useEffect(() => {
const defaultCategories = [
/* ALL_CATEGORY_NAME, */
@@ -74,7 +70,7 @@ export default function TemplateList({ environmentId, onTemplateClick }: Templat
return (
<main className="relative z-0 flex-1 overflow-y-auto px-6 pb-6 pt-3 focus:outline-none">
<div className="mb-6 flex flex-wrap space-x-2">
<div className="mb-6 flex flex-wrap gap-2">
{categories.map((category) => (
<button
key={category}
@@ -103,7 +99,7 @@ export default function TemplateList({ environmentId, onTemplateClick }: Templat
activeTemplate?.name === customSurvey.name
? "ring-brand border-transparent ring-2"
: "hover:border-brand-dark border-dashed border-slate-300",
"duration-120 group relative rounded-lg border-2 bg-transparent p-8 transition-colors duration-150"
"duration-120 group relative rounded-lg border-2 bg-transparent p-6 transition-colors duration-150"
)}>
<PlusCircleIcon className="text-brand-dark h-8 w-8 transition-all duration-150 group-hover:scale-110" />
<h3 className="text-md mb-1 mt-3 text-left font-bold text-slate-700 ">{customSurvey.name}</h3>
@@ -138,13 +134,41 @@ export default function TemplateList({ environmentId, onTemplateClick }: Templat
}}
key={template.name}
className={cn(
activeTemplate?.name === template.name && "ring-brand ring-2",
"duration-120 group relative cursor-pointer rounded-lg bg-white p-6 shadow transition-all duration-150 hover:scale-105"
activeTemplate?.name === template.name && "ring-2 ring-slate-400",
"duration-120 group relative cursor-pointer rounded-lg bg-white p-6 shadow transition-all duration-150 hover:scale-105"
)}>
<div className="absolute right-6 top-6 rounded border border-slate-300 bg-slate-50 px-1.5 py-0.5 text-xs text-slate-500">
{template.category}
<div className="flex">
<div
className={`rounded border px-1.5 py-0.5 text-xs ${
template.category === "Product Experience"
? "border-blue-300 bg-blue-50 text-blue-500"
: template.category === "Exploration"
? "border-pink-300 bg-pink-50 text-pink-500"
: template.category === "Growth"
? "border-orange-300 bg-orange-50 text-orange-500"
: template.category === "Increase Revenue"
? "border-emerald-300 bg-emerald-50 text-emerald-500"
: template.category === "Customer Success"
? "border-violet-300 bg-violet-50 text-violet-500"
: "border-slate-300 bg-slate-50 text-slate-500" // default color
}`}>
{template.category}
</div>
{template.preset.questions.some(
(question) => question.logic && question.logic.length > 0
) && (
<TooltipProvider delayDuration={80}>
<Tooltip>
<TooltipTrigger>
<div>
<SplitIcon className="ml-1.5 h-5 w-5 rounded border border-slate-300 bg-slate-50 p-0.5 text-slate-400" />
</div>
</TooltipTrigger>
<TooltipContent>This survey uses branching logic.</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
<template.icon className="h-8 w-8" />
<h3 className="text-md mb-1 mt-3 text-left font-bold text-slate-700">{template.name}</h3>
<p className="text-left text-xs text-slate-600">{template.description}</p>
{activeTemplate?.name === template.name && (

View File

@@ -72,13 +72,13 @@ export default function LinkSurvey({ survey }: LinkSurveyProps) {
case "notEquals":
return answerValue !== logic.value;
case "lessThan":
return answerValue < logic.value;
return logic.value !== undefined && answerValue < logic.value;
case "lessEqual":
return answerValue <= logic.value;
return logic.value !== undefined && answerValue <= logic.value;
case "greaterThan":
return answerValue > logic.value;
return logic.value !== undefined && answerValue > logic.value;
case "greaterEqual":
return answerValue >= logic.value;
return logic.value !== undefined && answerValue >= logic.value;
case "includesAll":
return (
Array.isArray(answerValue) &&

View File

@@ -11,6 +11,7 @@ import { GithubButton } from "./GithubButton";
export const SigninForm = () => {
const searchParams = useSearchParams();
const emailRef = useRef<HTMLInputElement>(null);
const handleSubmit = async (e) => {
setLoggingIn(true);
@@ -48,6 +49,7 @@ export const SigninForm = () => {
Email address
</label>
<input
ref={emailRef}
id="email"
name="email"
type="email"
@@ -90,6 +92,8 @@ export const SigninForm = () => {
if (!showLogin) {
setShowLogin(true);
setButtonEnabled(false);
// Add a slight delay before focusing the input field to ensure it's visible
setTimeout(() => emailRef.current?.focus(), 100);
} else if (formRef.current) {
formRef.current.requestSubmit();
}

View File

@@ -14,6 +14,7 @@ export const SignupForm = () => {
const router = useRouter();
const [error, setError] = useState<string>("");
const [signingUp, setSigningUp] = useState(false);
const nameRef = useRef<HTMLInputElement>(null);
const handleSubmit = async (e: any) => {
setSigningUp(true);
@@ -78,6 +79,7 @@ export const SignupForm = () => {
</label>
<div className="mt-1">
<input
ref={nameRef}
id="name"
name="name"
type="text"
@@ -136,6 +138,8 @@ export const SignupForm = () => {
if (!showLogin) {
setShowLogin(true);
setButtonEnabled(false);
// Add a slight delay before focusing the input field to ensure it's visible
setTimeout(() => nameRef.current?.focus(), 100);
} else if (formRef.current) {
formRef.current.requestSubmit();
}

View File

@@ -1,10 +1,10 @@
import { useState, useEffect } from "react";
import { Input } from "@/../../packages/ui";
import SubmitButton from "@/components/preview/SubmitButton";
import { cn } from "@formbricks/lib/cn";
import type { MultipleChoiceMultiQuestion } from "@formbricks/types/questions";
import { useEffect, useState } from "react";
import Headline from "./Headline";
import Subheader from "./Subheader";
import SubmitButton from "@/components/preview/SubmitButton";
import { Input } from "@/../../packages/ui";
interface MultipleChoiceMultiProps {
question: MultipleChoiceMultiQuestion;
@@ -46,7 +46,7 @@ export default function MultipleChoiceMultiQuestion({
};
onSubmit(data);
// console.log(data);
setSelectedChoices([]); // reset value
setShowOther(false);
setOtherSpecified("");
@@ -103,10 +103,9 @@ export default function MultipleChoiceMultiQuestion({
</span>
{choice.id === "other" && showOther && (
<Input
type="text"
id={`${choice.id}-label`}
name={question.id}
className="mt-2 bg-white"
className="mt-2 bg-white focus:border-slate-300"
placeholder="Please specify"
onChange={(e) => setOtherSpecified(e.currentTarget.value)}
aria-labelledby={`${choice.id}-label`}

View File

@@ -1,11 +1,10 @@
import { Input } from "@/../../packages/ui";
import SubmitButton from "@/components/preview/SubmitButton";
import { cn } from "@formbricks/lib/cn";
import type { MultipleChoiceSingleQuestion } from "@formbricks/types/questions";
import { useState } from "react";
import Headline from "./Headline";
import Subheader from "./Subheader";
import SubmitButton from "@/components/preview/SubmitButton";
import { Input } from "@/../../packages/ui";
import { useRef } from "react";
interface MultipleChoiceSingleProps {
question: MultipleChoiceSingleQuestion;
@@ -21,19 +20,15 @@ export default function MultipleChoiceSingleQuestion({
brandColor,
}: MultipleChoiceSingleProps) {
const [selectedChoice, setSelectedChoice] = useState<string | null>(null);
const otherSpecify = useRef<HTMLInputElement>(null);
return (
<form
onSubmit={(e) => {
e.preventDefault();
const value = otherSpecify.current?.value || e.currentTarget[question.id].value;
const value = e.currentTarget[question.id].value;
const data = {
[question.id]: value,
};
// console.log(data);
onSubmit(data);
setSelectedChoice(null); // reset form
}}>
@@ -70,12 +65,12 @@ export default function MultipleChoiceSingleQuestion({
</span>
{choice.id === "other" && selectedChoice === "other" && (
<Input
ref={otherSpecify}
id="other-specify"
name="other-specify"
id={`${choice.id}-label`}
name={question.id}
placeholder="Please specify"
className="mt-3 bg-white"
className="mt-3 bg-white focus:border-slate-300"
required={question.required}
aria-labelledby={`${choice.id}-label`}
autoFocus
/>
)}

View File

@@ -34,6 +34,7 @@ export default function OpenTextQuestion({
<Subheader subheader={question.subheader} questionId={question.id} />
<div className="mt-4">
<textarea
autoFocus
rows={3}
name={question.id}
id={question.id}

View File

@@ -1,9 +1,20 @@
export default function Progress({ progress, brandColor }: { progress: number; brandColor: string }) {
import React from "react";
const ProgressComponent = ({ progress, brandColor }) => {
return (
<div className="h-1 w-full rounded-full bg-slate-200">
<div
className="h-1 rounded-full bg-slate-700"
className="transition-width h-1 rounded-full duration-500"
style={{ backgroundColor: brandColor, width: `${Math.floor(progress * 100)}%` }}></div>
</div>
);
}
};
ProgressComponent.displayName = "Progress";
const Progress = React.memo(ProgressComponent, (prevProps, nextProps) => {
// Only re-render if progress or brandColor changes
return prevProps.progress === nextProps.progress && prevProps.brandColor === nextProps.brandColor;
});
export default Progress;

View File

@@ -51,7 +51,7 @@ export default function RatingQuestion({
type="radio"
name="rating"
value={number}
className="absolute h-full w-full cursor-pointer opacity-0"
className="absolute left-0 h-full w-full cursor-pointer opacity-0"
onChange={() => handleSelect(number)}
required={question.required}
/>

View File

@@ -108,6 +108,7 @@ export const getSettings = async (environmentId: string, personId: string): Prom
},
thankYouCard: true,
autoClose: true,
delay: true,
},
});
@@ -182,6 +183,7 @@ export const getSettings = async (environmentId: string, personId: string): Prom
triggers: survey.triggers,
thankYouCard: JSON.parse(JSON.stringify(survey.thankYouCard)),
autoClose: survey.autoClose,
delay: survey.delay,
};
});

View File

@@ -125,7 +125,9 @@ export const sendResponseFinishedEmail = async (
const personEmail = person?.attributes?.find((a) => a.attributeClass?.name === "email")?.value;
await sendEmail({
to: email,
subject: `A response for ${survey.name} was completed ✅`,
subject: personEmail
? `${personEmail} just completed your ${survey.name} survey ✅`
: `A response for ${survey.name} was completed ✅`,
replyTo: personEmail || process.env.MAIL_FROM,
html: withEmailTemplate(`<h1>Survey completed</h1>Someone just completed your survey "${survey.name}"<br/>
@@ -134,8 +136,6 @@ export const sendResponseFinishedEmail = async (
${getQuestionResponseMapping(survey, response)
.map((question) => `<p><strong>${question.question}</strong></p><p>${question.answer}</p>`)
.join("")}
<hr/>

View File

@@ -24,6 +24,8 @@ export const questionTypes: QuestionType[] = [
description: "A single line of text",
icon: ChatBubbleBottomCenterTextIcon,
preset: {
headline: "Who let the dogs out?",
subheader: "Who? Who? Who?",
placeholder: "Type your answer here...",
},
},

View File

@@ -1,9 +1,10 @@
{
"name": "@formbricks/api",
"version": "1.0.0",
"version": "0.1.0",
"description": "A Typescript API-wrapper for managing the Formbricks Client API.",
"license": "MIT",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"sideEffects": false,
"files": [

View File

@@ -1,8 +1,7 @@
{
"name": "@formbricks/database",
"private": true,
"version": "1.0.0",
"license": "MIT",
"version": "0.1.0",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Survey" ADD COLUMN "delay" INTEGER NOT NULL DEFAULT 0;

View File

@@ -199,6 +199,7 @@ model Survey {
attributeFilters SurveyAttributeFilter[]
displays Display[]
autoClose Int?
delay Int @default(0)
}
model Event {

View File

@@ -1,9 +1,10 @@
{
"name": "@formbricks/errors",
"description": "A helper package containing general error classes for Formbricks",
"private": true,
"version": "1.0.0",
"license": "MIT",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"sideEffects": false,
"files": [
@@ -14,8 +15,8 @@
"dev": "tsup --watch",
"lint": "eslint ./src --fix",
"clean": "rimraf .turbo node_modules dist"
},
"devDependencies": {
},
"devDependencies": {
"@formbricks/tsconfig": "workspace:*",
"eslint": "^8.41.0",
"eslint-config-formbricks": "workspace:*",

View File

@@ -13,7 +13,7 @@
setTimeout(function () {
window.formbricks = window.js;
window.formbricks.init({
environmentId: "clham12520003yz4zeng786vq",
environmentId: "clhkhwyc60003yz5rpgsgrebq",
apiHost: "http://localhost:3000",
logLevel: "debug",
});

View File

@@ -1,6 +1,7 @@
{
"name": "@formbricks/js",
"version": "0.1.19",
"license": "MIT",
"version": "0.1.20",
"description": "Formbricks-js allows you to connect your app to Formbricks, display surveys and trigger events.",
"keywords": [
"Formbricks",
@@ -22,10 +23,7 @@
},
"scripts": {
"clean": "rimraf .turbo node_modules dist",
"dev": "microbundle watch --css inline",
"start": "cross-env NODE_OPTIONS=--openssl-legacy-provider preact watch",
"build:widget": "microbundle --css inline",
"build:lib": "microbundle build -i src/component.tsx",
"dev": "microbundle --css inline",
"lint": "eslint '{src,tests}/**/*.{ts,tsx}'",
"test": "jest",
"build": "microbundle --css inline"
@@ -44,22 +42,19 @@
]
},
"author": "Formbricks <hola@formbricks.com>",
"license": "MIT",
"dependencies": {
"@formbricks/api": "workspace:*",
"@formbricks/errors": "workspace:*"
},
"dependencies": {},
"devDependencies": {
"@formbricks/api": "workspace:*",
"@formbricks/types": "workspace:*",
"@types/enzyme": "^3.10.13",
"@types/jest": "^29.5.2",
"@typescript-eslint/eslint-plugin": "^5.59.8",
"@typescript-eslint/parser": "^5.59.8",
"@typescript-eslint/eslint-plugin": "^5.59.9",
"@typescript-eslint/parser": "^5.59.9",
"autoprefixer": "^10.4.14",
"cross-env": "^7.0.3",
"enzyme": "^3.11.0",
"enzyme-adapter-preact-pure": "^4.1.0",
"eslint": "^8.41.0",
"eslint": "^8.42.0",
"eslint-config-formbricks": "workspace:*",
"eslint-config-preact": "^1.3.0",
"jest": "^29.5.0",
@@ -68,10 +63,10 @@
"postcss": "^8.4.24",
"preact": "10.15.1",
"preact-cli": "^3.4.5",
"preact-render-to-string": "^6.0.3",
"preact-render-to-string": "^6.1.0",
"rimraf": "^5.0.1",
"tailwindcss": "^3.3.2",
"typescript": "^5.0.4"
"typescript": "^5.1.3"
},
"jest": {
"preset": "jest-preset-preact",

View File

@@ -1,6 +1,6 @@
import type { MultipleChoiceMultiQuestion } from "../../../types/questions";
import { h } from "preact";
import { useState } from "preact/hooks";
import { useState, useRef, useEffect } from "preact/hooks";
import { cn } from "../lib/utils";
import Headline from "./Headline";
import Subheader from "./Subheader";
@@ -22,11 +22,18 @@ export default function MultipleChoiceMultiQuestion({
const [selectedChoices, setSelectedChoices] = useState<string[]>([]);
const [showOther, setShowOther] = useState(false);
const [otherSpecified, setOtherSpecified] = useState("");
const otherInputRef = useRef(null);
const isAtLeastOneChecked = () => {
return selectedChoices.length > 0 || otherSpecified.length > 0;
};
useEffect(() => {
if (showOther && otherInputRef.current) {
otherInputRef.current.focus();
}
}, [showOther]);
return (
<form
onSubmit={(e) => {
@@ -97,11 +104,13 @@ export default function MultipleChoiceMultiQuestion({
</span>
{choice.id === "other" && showOther && (
<input
type="text"
ref={otherInputRef}
id={`${choice.id}-label`}
name={question.id}
placeholder="Please specify"
className="fb-mt-3 fb-flex fb-h-10 fb-w-full fb-rounded-md fb-border fb-bg-white fb-border-slate-300 fb-bg-transparent fb-px-3 fb-py-2 fb-text-sm fb-text-slate-800 placeholder:fb-text-slate-400 focus:fb-outline-none focus:fb-ring-2 focus:fb-ring-slate-400 focus:fb-ring-offset-2 disabled:fb-cursor-not-allowed disabled:fb-opacity-50 dark:fb-border-slate-500 dark:fb-text-slate-300"
className={cn(
"fb-mt-3 fb-flex fb-h-10 fb-w-full fb-rounded-md fb-border fb-bg-white fb-border-slate-300 fb-bg-transparent fb-px-3 fb-py-2 fb-text-sm fb-text-slate-800 placeholder:fb-text-slate-400 focus:fb-outline-none focus:fb-ring-2 focus:fb-ring-slate-400 focus:fb-ring-offset-2 disabled:fb-cursor-not-allowed disabled:fb-opacity-50 dark:fb-border-slate-500 dark:fb-text-slate-300"
)}
onChange={(e) => setOtherSpecified(e.currentTarget.value)}
aria-labelledby={`${choice.id}-label`}
required={question.required}

View File

@@ -1,5 +1,5 @@
import { h } from "preact";
import { useRef, useState } from "preact/hooks";
import { useRef, useState, useEffect } from "preact/hooks";
import { cn } from "../lib/utils";
import type { MultipleChoiceSingleQuestion } from "../../../types/questions";
import Headline from "./Headline";
@@ -22,6 +22,12 @@ export default function MultipleChoiceSingleQuestion({
const [selectedChoice, setSelectedChoice] = useState<string | null>(null);
const otherSpecify = useRef<HTMLInputElement>(null);
useEffect(() => {
if (selectedChoice === "other") {
otherSpecify.current?.focus();
}
}, [selectedChoice]);
return (
<form
onSubmit={(e) => {
@@ -73,11 +79,12 @@ export default function MultipleChoiceSingleQuestion({
{choice.id === "other" && selectedChoice === "other" && (
<input
ref={otherSpecify}
id="other-specify"
name="other-specify"
id={`${choice.id}-label`}
name={question.id}
placeholder="Please specify"
className="fb-mt-3 fb-flex fb-h-10 fb-w-full fb-rounded-md fb-border fb-bg-white fb-border-slate-300 fb-bg-transparent fb-px-3 fb-py-2 fb-text-sm fb-text-slate-800 placeholder:fb-text-slate-400 focus:fb-outline-none focus:fb-ring-2 focus:fb-ring-slate-400 focus:fb-ring-offset-2 disabled:fb-cursor-not-allowed disabled:fb-opacity-50 dark:fb-border-slate-500 dark:fb-text-slate-300"
required={question.required}
aria-labelledby={`${choice.id}-label`}
/>
)}
</label>

View File

@@ -2,9 +2,9 @@ import { h } from "preact";
export default function Progress({ progress, brandColor }: { progress: number; brandColor: string }) {
return (
<div className="fb-h-1 fb-w-full fb-rounded-full bg-slate-200">
<div className="fb-h-1 fb-w-full fb-rounded-full fb-bg-slate-200">
<div
className="fb-h-1 fb-rounded-full"
className="fb-h-1 fb-rounded-full fb-transition-width fb-duration-500"
style={{ backgroundColor: brandColor, width: `${Math.floor(progress * 100)}%` }}></div>
</div>
);

View File

@@ -49,7 +49,7 @@ export default function RatingQuestion({
type="radio"
name="rating"
value={number}
className="fb-absolute fb-h-full fb-w-full fb-cursor-pointer fb-opacity-0"
className="fb-absolute fb-h-full fb-w-full fb-cursor-pointer fb-opacity-0 fb-left-0"
onChange={() => handleSelect(number)}
required={question.required}
/>

View File

@@ -101,13 +101,13 @@ export default function SurveyView({ config, survey, close, errorHandler }: Surv
case "notEquals":
return answerValue !== logic.value;
case "lessThan":
return answerValue < logic.value;
return logic.value !== undefined && answerValue < logic.value;
case "lessEqual":
return answerValue <= logic.value;
return logic.value !== undefined && answerValue <= logic.value;
case "greaterThan":
return answerValue > logic.value;
return logic.value !== undefined && answerValue > logic.value;
case "greaterEqual":
return answerValue >= logic.value;
return logic.value !== undefined && answerValue >= logic.value;
case "includesAll":
return (
Array.isArray(answerValue) &&

View File

@@ -1,4 +1,4 @@
import { EnvironmentId, FormbricksAPI } from "@formbricks/api";
import { FormbricksAPI, EnvironmentId } from "@formbricks/api";
import { Config } from "./config";
export const getApi = (): FormbricksAPI => {

View File

@@ -19,10 +19,16 @@ export const renderWidget = (survey: Survey) => {
}
surveyRunning = true;
render(
h(App, { config: config.get(), survey, closeSurvey, errorHandler: errorHandler.handle }),
document.getElementById(containerId)
);
if (survey.delay) {
logger.debug(`Delaying survey by ${survey.delay} seconds.`);
}
setTimeout(() => {
render(
h(App, { config: config.get(), survey, closeSurvey, errorHandler: errorHandler.handle }),
document.getElementById(containerId)
);
}, survey.delay * 1000);
};
export const closeSurvey = async (): Promise<void> => {

View File

@@ -5,7 +5,6 @@
"version": "0.0.0",
"main": "./index.ts",
"types": "./index.ts",
"license": "MIT",
"scripts": {
"clean": "rimraf .turbo node_modules .next",
"lint": "eslint . --ext .ts,.js,.tsx,.jsx",

View File

@@ -80,6 +80,7 @@ export interface Survey {
triggers: Trigger[];
thankYouCard: ThankYouCard;
autoClose?: number | null;
delay: number;
}
export interface Trigger {

View File

@@ -72,21 +72,21 @@ export type LogicCondition =
export interface LogicBase {
condition: LogicCondition | undefined;
value: number | string | string[] | undefined;
value?: number | string | string[] | undefined;
destination: string | "end" | undefined;
}
export interface OpenTextLogic extends LogicBase {
condition: "submitted" | "skipped" | undefined;
value: undefined;
value?: undefined;
}
export interface MultipleChoiceSingleLogic extends LogicBase {
condition: "submitted" | "skipped" | "equals" | "notEquals" | undefined;
value: string;
value?: string;
}
export interface MultipleChoiceMultiLogic extends LogicBase {
condition: "submitted" | "skipped" | "includesAll" | "includesOne" | undefined;
value: string[];
value?: string[];
}
export interface NPSLogic extends LogicBase {
condition:
@@ -99,11 +99,11 @@ export interface NPSLogic extends LogicBase {
| "equals"
| "notEquals"
| undefined;
value: number;
value?: number;
}
export interface CTALogic extends LogicBase {
condition: "submitted" | "skipped" | undefined;
value: undefined;
value?: undefined;
}
export interface RatingLogic extends LogicBase {
condition:
@@ -116,7 +116,7 @@ export interface RatingLogic extends LogicBase {
| "equals"
| "notEquals"
| undefined;
value: number;
value?: number | string;
}
export type Logic =
| OpenTextLogic

View File

@@ -23,6 +23,7 @@ export interface Survey {
displayOption: "displayOnce" | "displayMultiple" | "respondMultiple";
attributeFilters: AttributeFilter[];
autoClose: number | null;
delay: number;
}
export interface AttributeFilter {

View File

@@ -10,8 +10,8 @@ export type Objective =
export interface Template {
name: string;
icon: any;
description: string;
icon?: any;
category?: "Product Experience" | "Exploration" | "Growth" | "Increase Revenue" | "Customer Success";
objectives?: [Objective, Objective?, Objective?];
preset: {

366
pnpm-lock.yaml generated
View File

@@ -468,7 +468,7 @@ importers:
version: 8.41.0
eslint-config-next:
specifier: ^13.4.4
version: 13.4.4(eslint@8.41.0)
version: 13.4.4(eslint@8.41.0)(typescript@5.1.3)
eslint-config-prettier:
specifier: ^8.8.0
version: 8.8.0(eslint@8.41.0)
@@ -484,14 +484,10 @@ importers:
version: 5.0.1
packages/js:
dependencies:
devDependencies:
'@formbricks/api':
specifier: workspace:*
version: link:../api
'@formbricks/errors':
specifier: workspace:*
version: link:../errors
devDependencies:
'@formbricks/types':
specifier: workspace:*
version: link:../types
@@ -502,11 +498,11 @@ importers:
specifier: ^29.5.2
version: 29.5.2
'@typescript-eslint/eslint-plugin':
specifier: ^5.59.8
version: 5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.41.0)(typescript@5.0.4)
specifier: ^5.59.9
version: 5.59.9(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.1.3)
'@typescript-eslint/parser':
specifier: ^5.59.8
version: 5.59.8(eslint@8.41.0)(typescript@5.0.4)
specifier: ^5.59.9
version: 5.59.9(eslint@8.42.0)(typescript@5.1.3)
autoprefixer:
specifier: ^10.4.14
version: 10.4.14(postcss@8.4.24)
@@ -520,20 +516,20 @@ importers:
specifier: ^4.1.0
version: 4.1.0(enzyme@3.11.0)(preact@10.15.1)
eslint:
specifier: ^8.41.0
version: 8.41.0
specifier: ^8.42.0
version: 8.42.0
eslint-config-formbricks:
specifier: workspace:*
version: link:../eslint-config-formbricks
eslint-config-preact:
specifier: ^1.3.0
version: 1.3.0(@typescript-eslint/eslint-plugin@5.59.8)(eslint@8.41.0)(jest@29.5.0)(typescript@5.0.4)
version: 1.3.0(@typescript-eslint/eslint-plugin@5.59.9)(eslint@8.42.0)(jest@29.5.0)(typescript@5.1.3)
jest:
specifier: ^29.5.0
version: 29.5.0
jest-preset-preact:
specifier: ^4.0.5
version: 4.0.5(jest@29.5.0)(preact-render-to-string@6.0.3)(preact@10.15.1)
version: 4.0.5(jest@29.5.0)(preact-render-to-string@6.1.0)(preact@10.15.1)
microbundle:
specifier: ^0.15.1
version: 0.15.1
@@ -545,10 +541,10 @@ importers:
version: 10.15.1
preact-cli:
specifier: ^3.4.5
version: 3.4.5(eslint@8.41.0)(preact-render-to-string@6.0.3)(preact@10.15.1)
version: 3.4.5(eslint@8.42.0)(preact-render-to-string@6.1.0)(preact@10.15.1)
preact-render-to-string:
specifier: ^6.0.3
version: 6.0.3(preact@10.15.1)
specifier: ^6.1.0
version: 6.1.0(preact@10.15.1)
rimraf:
specifier: ^5.0.1
version: 5.0.1
@@ -556,8 +552,8 @@ importers:
specifier: ^3.3.2
version: 3.3.2
typescript:
specifier: ^5.0.4
version: 5.0.4
specifier: ^5.1.3
version: 5.1.3
packages/lib:
devDependencies:
@@ -890,7 +886,7 @@ packages:
- supports-color
dev: true
/@babel/eslint-parser@7.19.1(@babel/core@7.20.12)(eslint@8.41.0):
/@babel/eslint-parser@7.19.1(@babel/core@7.20.12)(eslint@8.42.0):
resolution: {integrity: sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==}
engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0}
peerDependencies:
@@ -899,7 +895,7 @@ packages:
dependencies:
'@babel/core': 7.20.12
'@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1
eslint: 8.41.0
eslint: 8.42.0
eslint-visitor-keys: 2.1.0
semver: 6.3.0
dev: true
@@ -2703,6 +2699,16 @@ packages:
eslint: 8.41.0
eslint-visitor-keys: 3.4.1
/@eslint-community/eslint-utils@4.2.0(eslint@8.42.0):
resolution: {integrity: sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
dependencies:
eslint: 8.42.0
eslint-visitor-keys: 3.4.1
dev: true
/@eslint-community/regexpp@4.4.0:
resolution: {integrity: sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
@@ -2749,6 +2755,11 @@ packages:
resolution: {integrity: sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
/@eslint/js@8.42.0:
resolution: {integrity: sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/@floating-ui/core@0.7.3:
resolution: {integrity: sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==}
dev: false
@@ -2826,6 +2837,17 @@ packages:
react: 18.2.0
dev: false
/@humanwhocodes/config-array@0.11.10:
resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==}
engines: {node: '>=10.10.0'}
dependencies:
'@humanwhocodes/object-schema': 1.2.1
debug: 4.3.4
minimatch: 3.1.2
transitivePeerDependencies:
- supports-color
dev: true
/@humanwhocodes/config-array@0.11.8:
resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==}
engines: {node: '>=10.10.0'}
@@ -5490,7 +5512,7 @@ packages:
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1'
dependencies:
mini-svg-data-uri: 1.4.4
tailwindcss: 3.3.1(postcss@8.4.22)
tailwindcss: 3.3.1(postcss@8.4.21)
dev: true
/@tailwindcss/forms@0.5.3(tailwindcss@3.3.2):
@@ -6001,8 +6023,8 @@ packages:
'@types/yargs-parser': 21.0.0
dev: true
/@typescript-eslint/eslint-plugin@5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.41.0)(typescript@5.0.4):
resolution: {integrity: sha512-JDMOmhXteJ4WVKOiHXGCoB96ADWg9q7efPWHRViT/f09bA8XOMLAVHHju3l0MkZnG1izaWXYmgvQcUjTRcpShQ==}
/@typescript-eslint/eslint-plugin@5.59.9(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.1.3):
resolution: {integrity: sha512-4uQIBq1ffXd2YvF7MAvehWKW3zVv/w+mSfRAu+8cKbfj3nwzyqJLNcZJpQ/WZ1HLbJDiowwmQ6NO+63nCA+fqA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
'@typescript-eslint/parser': ^5.0.0
@@ -6013,30 +6035,30 @@ packages:
optional: true
dependencies:
'@eslint-community/regexpp': 4.4.0
'@typescript-eslint/parser': 5.59.8(eslint@8.41.0)(typescript@5.0.4)
'@typescript-eslint/scope-manager': 5.59.8
'@typescript-eslint/type-utils': 5.59.8(eslint@8.41.0)(typescript@5.0.4)
'@typescript-eslint/utils': 5.59.8(eslint@8.41.0)(typescript@5.0.4)
'@typescript-eslint/parser': 5.59.9(eslint@8.42.0)(typescript@5.1.3)
'@typescript-eslint/scope-manager': 5.59.9
'@typescript-eslint/type-utils': 5.59.9(eslint@8.42.0)(typescript@5.1.3)
'@typescript-eslint/utils': 5.59.9(eslint@8.42.0)(typescript@5.1.3)
debug: 4.3.4
eslint: 8.41.0
eslint: 8.42.0
grapheme-splitter: 1.0.4
ignore: 5.2.1
natural-compare-lite: 1.4.0
semver: 7.3.8
tsutils: 3.21.0(typescript@5.0.4)
typescript: 5.0.4
tsutils: 3.21.0(typescript@5.1.3)
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/experimental-utils@5.54.0(eslint@8.41.0)(typescript@5.0.4):
/@typescript-eslint/experimental-utils@5.54.0(eslint@8.42.0)(typescript@5.1.3):
resolution: {integrity: sha512-rRYECOTh5V3iWsrOzXi7h1jp3Bi9OkJHrb3wECi3DVqMGTilo9wAYmCbT+6cGdrzUY3MWcAa2mESM6FMik6tVw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
'@typescript-eslint/utils': 5.54.0(eslint@8.41.0)(typescript@5.0.4)
eslint: 8.41.0
'@typescript-eslint/utils': 5.54.0(eslint@8.42.0)(typescript@5.1.3)
eslint: 8.42.0
transitivePeerDependencies:
- supports-color
- typescript
@@ -6062,7 +6084,7 @@ packages:
- supports-color
dev: false
/@typescript-eslint/parser@5.59.8(eslint@8.41.0)(typescript@5.0.4):
/@typescript-eslint/parser@5.59.8(eslint@8.41.0)(typescript@5.1.3):
resolution: {integrity: sha512-AnR19RjJcpjoeGojmwZtCwBX/RidqDZtzcbG3xHrmz0aHHoOcbWnpDllenRDmDvsV0RQ6+tbb09/kyc+UT9Orw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -6074,12 +6096,33 @@ packages:
dependencies:
'@typescript-eslint/scope-manager': 5.59.8
'@typescript-eslint/types': 5.59.8
'@typescript-eslint/typescript-estree': 5.59.8(typescript@5.0.4)
'@typescript-eslint/typescript-estree': 5.59.8(typescript@5.1.3)
debug: 4.3.4
eslint: 8.41.0
typescript: 5.0.4
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: false
/@typescript-eslint/parser@5.59.9(eslint@8.42.0)(typescript@5.1.3):
resolution: {integrity: sha512-FsPkRvBtcLQ/eVK1ivDiNYBjn3TGJdXy2fhXX+rc7czWl4ARwnpArwbihSOHI2Peg9WbtGHrbThfBUkZZGTtvQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/scope-manager': 5.59.9
'@typescript-eslint/types': 5.59.9
'@typescript-eslint/typescript-estree': 5.59.9(typescript@5.1.3)
debug: 4.3.4
eslint: 8.42.0
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/scope-manager@5.54.0:
resolution: {integrity: sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==}
@@ -6103,9 +6146,18 @@ packages:
dependencies:
'@typescript-eslint/types': 5.59.8
'@typescript-eslint/visitor-keys': 5.59.8
dev: false
/@typescript-eslint/type-utils@5.59.8(eslint@8.41.0)(typescript@5.0.4):
resolution: {integrity: sha512-+5M518uEIHFBy3FnyqZUF3BMP+AXnYn4oyH8RF012+e7/msMY98FhGL5SrN29NQ9xDgvqCgYnsOiKp1VjZ/fpA==}
/@typescript-eslint/scope-manager@5.59.9:
resolution: {integrity: sha512-8RA+E+w78z1+2dzvK/tGZ2cpGigBZ58VMEHDZtpE1v+LLjzrYGc8mMaTONSxKyEkz3IuXFM0IqYiGHlCsmlZxQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
'@typescript-eslint/types': 5.59.9
'@typescript-eslint/visitor-keys': 5.59.9
dev: true
/@typescript-eslint/type-utils@5.59.9(eslint@8.42.0)(typescript@5.1.3):
resolution: {integrity: sha512-ksEsT0/mEHg9e3qZu98AlSrONAQtrSTljL3ow9CGej8eRo7pe+yaC/mvTjptp23Xo/xIf2mLZKC6KPv4Sji26Q==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: '*'
@@ -6114,12 +6166,12 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/typescript-estree': 5.59.8(typescript@5.0.4)
'@typescript-eslint/utils': 5.59.8(eslint@8.41.0)(typescript@5.0.4)
'@typescript-eslint/typescript-estree': 5.59.9(typescript@5.1.3)
'@typescript-eslint/utils': 5.59.9(eslint@8.42.0)(typescript@5.1.3)
debug: 4.3.4
eslint: 8.41.0
tsutils: 3.21.0(typescript@5.0.4)
typescript: 5.0.4
eslint: 8.42.0
tsutils: 3.21.0(typescript@5.1.3)
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: true
@@ -6137,8 +6189,14 @@ packages:
/@typescript-eslint/types@5.59.8:
resolution: {integrity: sha512-+uWuOhBTj/L6awoWIg0BlWy0u9TyFpCHrAuQ5bNfxDaZ1Ppb3mx6tUigc74LHcbHpOHuOTOJrBoAnhdHdaea1w==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: false
/@typescript-eslint/typescript-estree@5.54.0(typescript@5.0.4):
/@typescript-eslint/types@5.59.9:
resolution: {integrity: sha512-uW8H5NRgTVneSVTfiCVffBb8AbwWSKg7qcA4Ot3JI3MPCJGsB4Db4BhvAODIIYE5mNj7Q+VJkK7JxmRhk2Lyjw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/@typescript-eslint/typescript-estree@5.54.0(typescript@5.1.3):
resolution: {integrity: sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -6153,8 +6211,8 @@ packages:
globby: 11.1.0
is-glob: 4.0.3
semver: 7.3.8
tsutils: 3.21.0(typescript@5.0.4)
typescript: 5.0.4
tsutils: 3.21.0(typescript@5.1.3)
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: true
@@ -6180,7 +6238,7 @@ packages:
- supports-color
dev: false
/@typescript-eslint/typescript-estree@5.59.8(typescript@5.0.4):
/@typescript-eslint/typescript-estree@5.59.8(typescript@5.1.3):
resolution: {integrity: sha512-Jy/lPSDJGNow14vYu6IrW790p7HIf/SOV1Bb6lZ7NUkLc2iB2Z9elESmsaUtLw8kVqogSbtLH9tut5GCX1RLDg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -6195,12 +6253,34 @@ packages:
globby: 11.1.0
is-glob: 4.0.3
semver: 7.3.8
tsutils: 3.21.0(typescript@5.0.4)
typescript: 5.0.4
tsutils: 3.21.0(typescript@5.1.3)
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: false
/@typescript-eslint/utils@5.54.0(eslint@8.41.0)(typescript@5.0.4):
/@typescript-eslint/typescript-estree@5.59.9(typescript@5.1.3):
resolution: {integrity: sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/types': 5.59.9
'@typescript-eslint/visitor-keys': 5.59.9
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
semver: 7.3.8
tsutils: 3.21.0(typescript@5.1.3)
typescript: 5.1.3
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/utils@5.54.0(eslint@8.42.0)(typescript@5.1.3):
resolution: {integrity: sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -6210,29 +6290,29 @@ packages:
'@types/semver': 7.3.13
'@typescript-eslint/scope-manager': 5.54.0
'@typescript-eslint/types': 5.54.0
'@typescript-eslint/typescript-estree': 5.54.0(typescript@5.0.4)
eslint: 8.41.0
'@typescript-eslint/typescript-estree': 5.54.0(typescript@5.1.3)
eslint: 8.42.0
eslint-scope: 5.1.1
eslint-utils: 3.0.0(eslint@8.41.0)
eslint-utils: 3.0.0(eslint@8.42.0)
semver: 7.3.8
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/@typescript-eslint/utils@5.59.8(eslint@8.41.0)(typescript@5.0.4):
resolution: {integrity: sha512-Tr65630KysnNn9f9G7ROF3w1b5/7f6QVCJ+WK9nhIocWmx9F+TmCAcglF26Vm7z8KCTwoKcNEBZrhlklla3CKg==}
/@typescript-eslint/utils@5.59.9(eslint@8.42.0)(typescript@5.1.3):
resolution: {integrity: sha512-1PuMYsju/38I5Ggblaeb98TOoUvjhRvLpLa1DoTOFaLWqaXl/1iQ1eGurTXgBY58NUdtfTXKP5xBq7q9NDaLKg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
'@eslint-community/eslint-utils': 4.2.0(eslint@8.41.0)
'@eslint-community/eslint-utils': 4.2.0(eslint@8.42.0)
'@types/json-schema': 7.0.11
'@types/semver': 7.3.13
'@typescript-eslint/scope-manager': 5.59.8
'@typescript-eslint/types': 5.59.8
'@typescript-eslint/typescript-estree': 5.59.8(typescript@5.0.4)
eslint: 8.41.0
'@typescript-eslint/scope-manager': 5.59.9
'@typescript-eslint/types': 5.59.9
'@typescript-eslint/typescript-estree': 5.59.9(typescript@5.1.3)
eslint: 8.42.0
eslint-scope: 5.1.1
semver: 7.3.8
transitivePeerDependencies:
@@ -6262,6 +6342,15 @@ packages:
dependencies:
'@typescript-eslint/types': 5.59.8
eslint-visitor-keys: 3.4.1
dev: false
/@typescript-eslint/visitor-keys@5.59.9:
resolution: {integrity: sha512-bT7s0td97KMaLwpEBckbzj/YohnvXtqbe2XgqNvTl6RJVakY5mvENOTPvw5u66nljfZxthESpDozs86U+oLY8Q==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
'@typescript-eslint/types': 5.59.9
eslint-visitor-keys: 3.4.1
dev: true
/@webassemblyjs/ast@1.11.1:
resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==}
@@ -9957,7 +10046,7 @@ packages:
- supports-color
dev: false
/eslint-config-next@13.4.4(eslint@8.41.0):
/eslint-config-next@13.4.4(eslint@8.41.0)(typescript@5.1.3):
resolution: {integrity: sha512-z/PMbm6L0iC/fwISULxe8IVy4DtNqZk2wQY711o35klenq70O6ns82A8yuMVCFjHC0DIyB2lyugesRtuk9u8dQ==}
peerDependencies:
eslint: ^7.23.0 || ^8.0.0
@@ -9968,7 +10057,7 @@ packages:
dependencies:
'@next/eslint-plugin-next': 13.4.4
'@rushstack/eslint-patch': 1.2.0
'@typescript-eslint/parser': 5.59.8(eslint@8.41.0)(typescript@5.0.4)
'@typescript-eslint/parser': 5.59.8(eslint@8.41.0)(typescript@5.1.3)
eslint: 8.41.0
eslint-import-resolver-node: 0.3.6
eslint-import-resolver-typescript: 3.5.2(eslint-plugin-import@2.26.0)(eslint@8.41.0)
@@ -9976,26 +10065,27 @@ packages:
eslint-plugin-jsx-a11y: 6.6.1(eslint@8.41.0)
eslint-plugin-react: 7.32.2(eslint@8.41.0)
eslint-plugin-react-hooks: 4.6.0(eslint@8.41.0)
typescript: 5.1.3
transitivePeerDependencies:
- eslint-import-resolver-webpack
- supports-color
dev: false
/eslint-config-preact@1.3.0(@typescript-eslint/eslint-plugin@5.59.8)(eslint@8.41.0)(jest@29.5.0)(typescript@5.0.4):
/eslint-config-preact@1.3.0(@typescript-eslint/eslint-plugin@5.59.9)(eslint@8.42.0)(jest@29.5.0)(typescript@5.1.3):
resolution: {integrity: sha512-yHYXg5qNzEJd3D/30AmsIW0W8MuY858KpApXp7xxBF08IYUljSKCOqMx+dVucXHQnAm7+11wOnMkgVHIBAechw==}
peerDependencies:
eslint: 6.x || 7.x || 8.x
dependencies:
'@babel/core': 7.20.12
'@babel/eslint-parser': 7.19.1(@babel/core@7.20.12)(eslint@8.41.0)
'@babel/eslint-parser': 7.19.1(@babel/core@7.20.12)(eslint@8.42.0)
'@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.20.12)
'@babel/plugin-syntax-decorators': 7.19.0(@babel/core@7.20.12)
'@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.20.12)
eslint: 8.41.0
eslint-plugin-compat: 4.1.2(eslint@8.41.0)
eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.59.8)(eslint@8.41.0)(jest@29.5.0)(typescript@5.0.4)
eslint-plugin-react: 7.32.2(eslint@8.41.0)
eslint-plugin-react-hooks: 4.6.0(eslint@8.41.0)
eslint: 8.42.0
eslint-plugin-compat: 4.1.2(eslint@8.42.0)
eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.59.9)(eslint@8.42.0)(jest@29.5.0)(typescript@5.1.3)
eslint-plugin-react: 7.32.2(eslint@8.42.0)
eslint-plugin-react-hooks: 4.6.0(eslint@8.42.0)
transitivePeerDependencies:
- '@typescript-eslint/eslint-plugin'
- jest
@@ -10071,7 +10161,7 @@ packages:
eslint-import-resolver-webpack:
optional: true
dependencies:
'@typescript-eslint/parser': 5.59.8(eslint@8.41.0)(typescript@5.0.4)
'@typescript-eslint/parser': 5.59.8(eslint@8.41.0)(typescript@5.1.3)
debug: 3.2.7
eslint: 8.41.0
eslint-import-resolver-node: 0.3.6
@@ -10080,7 +10170,7 @@ packages:
- supports-color
dev: false
/eslint-plugin-compat@4.1.2(eslint@8.41.0):
/eslint-plugin-compat@4.1.2(eslint@8.42.0):
resolution: {integrity: sha512-DNrQgDi5L4mAL4FdFboKBlSRg6MWfd75eA7K91lMjtP5ryN+O11qT2FDn7Z6zqy6sZ4sJawUR5V75qzB6l0CBg==}
engines: {node: '>=16.x'}
peerDependencies:
@@ -10090,7 +10180,7 @@ packages:
ast-metadata-inferer: 0.7.0
browserslist: 4.21.5
caniuse-lite: 1.0.30001466
eslint: 8.41.0
eslint: 8.42.0
find-up: 5.0.0
lodash.memoize: 4.1.2
semver: 7.3.8
@@ -10106,7 +10196,7 @@ packages:
'@typescript-eslint/parser':
optional: true
dependencies:
'@typescript-eslint/parser': 5.59.8(eslint@8.41.0)(typescript@5.0.4)
'@typescript-eslint/parser': 5.59.8(eslint@8.41.0)(typescript@5.1.3)
array-includes: 3.1.6
array.prototype.flat: 1.3.1
debug: 2.6.9
@@ -10127,7 +10217,7 @@ packages:
- supports-color
dev: false
/eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@5.59.8)(eslint@8.41.0)(jest@29.5.0)(typescript@5.0.4):
/eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@5.59.9)(eslint@8.42.0)(jest@29.5.0)(typescript@5.1.3):
resolution: {integrity: sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
peerDependencies:
@@ -10140,9 +10230,9 @@ packages:
jest:
optional: true
dependencies:
'@typescript-eslint/eslint-plugin': 5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.41.0)(typescript@5.0.4)
'@typescript-eslint/experimental-utils': 5.54.0(eslint@8.41.0)(typescript@5.0.4)
eslint: 8.41.0
'@typescript-eslint/eslint-plugin': 5.59.9(@typescript-eslint/parser@5.59.9)(eslint@8.42.0)(typescript@5.1.3)
'@typescript-eslint/experimental-utils': 5.54.0(eslint@8.42.0)(typescript@5.1.3)
eslint: 8.42.0
jest: 29.5.0
transitivePeerDependencies:
- supports-color
@@ -10178,6 +10268,16 @@ packages:
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
dependencies:
eslint: 8.41.0
dev: false
/eslint-plugin-react-hooks@4.6.0(eslint@8.42.0):
resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==}
engines: {node: '>=10'}
peerDependencies:
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
dependencies:
eslint: 8.42.0
dev: true
/eslint-plugin-react@7.32.2(eslint@8.41.0):
resolution: {integrity: sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==}
@@ -10201,6 +10301,31 @@ packages:
resolve: 2.0.0-next.4
semver: 6.3.0
string.prototype.matchall: 4.0.8
dev: false
/eslint-plugin-react@7.32.2(eslint@8.42.0):
resolution: {integrity: sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==}
engines: {node: '>=4'}
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
dependencies:
array-includes: 3.1.6
array.prototype.flatmap: 1.3.1
array.prototype.tosorted: 1.1.1
doctrine: 2.1.0
eslint: 8.42.0
estraverse: 5.3.0
jsx-ast-utils: 3.3.3
minimatch: 3.1.2
object.entries: 1.1.6
object.fromentries: 2.0.6
object.hasown: 1.1.2
object.values: 1.1.6
prop-types: 15.8.1
resolve: 2.0.0-next.4
semver: 6.3.0
string.prototype.matchall: 4.0.8
dev: true
/eslint-plugin-turbo@1.8.8(eslint@8.41.0):
resolution: {integrity: sha512-zqyTIvveOY4YU5jviDWw9GXHd4RiKmfEgwsjBrV/a965w0PpDwJgEUoSMB/C/dU310Sv9mF3DSdEjxjJLaw6rA==}
@@ -10240,13 +10365,13 @@ packages:
esrecurse: 4.3.0
estraverse: 5.3.0
/eslint-utils@3.0.0(eslint@8.41.0):
/eslint-utils@3.0.0(eslint@8.42.0):
resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
peerDependencies:
eslint: '>=5'
dependencies:
eslint: 8.41.0
eslint: 8.42.0
eslint-visitor-keys: 2.1.0
dev: true
@@ -10360,6 +10485,54 @@ packages:
transitivePeerDependencies:
- supports-color
/eslint@8.42.0:
resolution: {integrity: sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true
dependencies:
'@eslint-community/eslint-utils': 4.2.0(eslint@8.42.0)
'@eslint-community/regexpp': 4.4.0
'@eslint/eslintrc': 2.0.3
'@eslint/js': 8.42.0
'@humanwhocodes/config-array': 0.11.10
'@humanwhocodes/module-importer': 1.0.1
'@nodelib/fs.walk': 1.2.8
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.3
debug: 4.3.4
doctrine: 3.0.0
escape-string-regexp: 4.0.0
eslint-scope: 7.2.0
eslint-visitor-keys: 3.4.1
espree: 9.5.2
esquery: 1.5.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
file-entry-cache: 6.0.1
find-up: 5.0.0
glob-parent: 6.0.2
globals: 13.19.0
graphemer: 1.4.0
ignore: 5.2.1
import-fresh: 3.3.0
imurmurhash: 0.1.4
is-glob: 4.0.3
is-path-inside: 3.0.3
js-yaml: 4.1.0
json-stable-stringify-without-jsonify: 1.0.1
levn: 0.4.1
lodash.merge: 4.6.2
minimatch: 3.1.2
natural-compare: 1.4.0
optionator: 0.9.1
strip-ansi: 6.0.1
strip-json-comments: 3.1.1
text-table: 0.2.0
transitivePeerDependencies:
- supports-color
dev: true
/esm@3.2.25:
resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==}
engines: {node: '>=6'}
@@ -10862,7 +11035,7 @@ packages:
resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
dev: true
/fork-ts-checker-webpack-plugin@4.1.6(eslint@8.41.0)(typescript@4.6.4)(webpack@4.46.0):
/fork-ts-checker-webpack-plugin@4.1.6(eslint@8.42.0)(typescript@4.6.4)(webpack@4.46.0):
resolution: {integrity: sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==}
engines: {node: '>=6.11.5', yarn: '>=1.0.0'}
peerDependencies:
@@ -10878,7 +11051,7 @@ packages:
dependencies:
'@babel/code-frame': 7.18.6
chalk: 2.4.2
eslint: 8.41.0
eslint: 8.42.0
micromatch: 3.1.10
minimatch: 3.1.2
semver: 5.7.1
@@ -12798,7 +12971,7 @@ packages:
jest-resolve: 29.5.0
dev: true
/jest-preset-preact@4.0.5(jest@29.5.0)(preact-render-to-string@6.0.3)(preact@10.15.1):
/jest-preset-preact@4.0.5(jest@29.5.0)(preact-render-to-string@6.1.0)(preact@10.15.1):
resolution: {integrity: sha512-MnU7mfpnwopJkdx0WoEyRmrNDIvRN+w6sOur0zEhaRYYMo0gJM7UdZHWTV8k6uo0+ypY+m0kQW6kMukUx4v8JQ==}
peerDependencies:
jest: 26.x || 27.x
@@ -12816,7 +12989,7 @@ packages:
jest: 29.5.0
jest-watch-typeahead: 0.6.5(jest@29.5.0)
preact: 10.15.1
preact-render-to-string: 6.0.3(preact@10.15.1)
preact-render-to-string: 6.1.0(preact@10.15.1)
transitivePeerDependencies:
- encoding
- supports-color
@@ -16688,7 +16861,7 @@ packages:
- debug
dev: false
/preact-cli@3.4.5(eslint@8.41.0)(preact-render-to-string@6.0.3)(preact@10.15.1):
/preact-cli@3.4.5(eslint@8.42.0)(preact-render-to-string@6.1.0)(preact@10.15.1):
resolution: {integrity: sha512-pLTawiXDy4rEct5ul0mDCP92GB6NK/QFhpoR+iHZJqgkeyE25qEXPf1/tJhAiijphDL5kxGvsT4qA6SrpQ5BsQ==}
engines: {node: '>=12'}
hasBin: true
@@ -16736,7 +16909,7 @@ packages:
envinfo: 7.8.1
esm: 3.2.25
file-loader: 6.2.0(webpack@4.46.0)
fork-ts-checker-webpack-plugin: 4.1.6(eslint@8.41.0)(typescript@4.6.4)(webpack@4.46.0)
fork-ts-checker-webpack-plugin: 4.1.6(eslint@8.42.0)(typescript@4.6.4)(webpack@4.46.0)
get-port: 5.1.1
gittar: 0.1.1
glob: 8.1.0
@@ -16756,7 +16929,7 @@ packages:
postcss-load-config: 3.1.4(postcss@8.4.24)
postcss-loader: 4.3.0(postcss@8.4.24)(webpack@4.46.0)
preact: 10.15.1
preact-render-to-string: 6.0.3(preact@10.15.1)
preact-render-to-string: 6.1.0(preact@10.15.1)
progress-bar-webpack-plugin: 2.1.0(webpack@4.46.0)
promise-polyfill: 8.3.0
prompts: 2.4.2
@@ -16812,8 +16985,8 @@ packages:
pretty-format: 3.8.0
dev: false
/preact-render-to-string@6.0.3(preact@10.15.1):
resolution: {integrity: sha512-UUP+EtmLw5ns0fT9C7+CTdLawm1wLmlrZ6WKzJ4Jwhb4EBu4vy5ufIZKlrfvWNnPl1JFoJzZwzfKs97H4N0Vug==}
/preact-render-to-string@6.1.0(preact@10.15.1):
resolution: {integrity: sha512-/AsKU4Q4R8r4aKwwNQrkQQNUVEDmTeZr6IwesDffobFRPcTk4dSQrfo1VOcXjtlcUss6QYEe7JShUGbQIhaw+A==}
peerDependencies:
preact: '>=10'
dependencies:
@@ -19818,6 +19991,16 @@ packages:
dependencies:
tslib: 1.14.1
typescript: 5.0.4
dev: false
/tsutils@3.21.0(typescript@5.1.3):
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
dependencies:
tslib: 1.14.1
typescript: 5.1.3
/tsx@3.12.6:
resolution: {integrity: sha512-q93WgS3lBdHlPgS0h1i+87Pt6n9K/qULIMNYZo07nSeu2z5QE2CellcAZfofVXBo2tQg9av2ZcRMQ2S2i5oadQ==}
@@ -20018,6 +20201,11 @@ packages:
engines: {node: '>=12.20'}
hasBin: true
/typescript@5.1.3:
resolution: {integrity: sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==}
engines: {node: '>=14.17'}
hasBin: true
/uc.micro@1.0.6:
resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==}
dev: false