Applied stash to newly merged

pull/2150/head
Alex van Andel 2022-02-18 21:52:16 +01:00
parent 801fd6d2f8
commit 10cf649189
17 changed files with 319 additions and 105 deletions

View File

@ -1,11 +1,8 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"editor.formatOnSave": true,
// Auto-fix issues with ESLint when you save code changes
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.run": "onSave",
"typescript.preferences.importModuleSpecifier": "non-relative",
"spellright.language": ["en"],
"spellright.documentTypes": ["markdown"]

View File

@ -299,9 +299,9 @@ export default function Shell(props: {
</Button>
</div>
)}
<div className="block min-h-[80px] justify-between px-4 sm:flex sm:px-6 md:px-8">
<div className="block justify-between px-4 sm:flex sm:px-6 md:px-8">
{props.HeadingLeftIcon && <div className="ltr:mr-4">{props.HeadingLeftIcon}</div>}
<div className="mb-8 w-full">
<div className={classNames("w-full", props.subtitle ? "mb-8" : "mb-2")}>
<h1 className="font-cal mb-1 text-xl font-bold tracking-wide text-gray-900">
{props.heading}
</h1>

View File

@ -139,7 +139,7 @@ const ScheduleBlock = ({ name, day, weekday }: ScheduleBlockProps) => {
};
return (
<fieldset className="flex min-h-[86px] flex-col justify-between space-y-2 py-5 sm:flex-row sm:space-y-0">
<fieldset className="flex flex-col justify-between space-y-2 py-5 sm:flex-row sm:space-y-0">
<div className="w-1/3">
<label className="flex items-center space-x-2 rtl:space-x-reverse">
<input

View File

@ -1,4 +1,4 @@
import { CheckCircleIcon, InformationCircleIcon, XCircleIcon } from "@heroicons/react/solid";
import { CheckCircleIcon, ExclamationIcon, InformationCircleIcon, XCircleIcon } from "@heroicons/react/solid";
import classNames from "classnames";
import { ReactNode } from "react";
@ -7,7 +7,7 @@ export interface AlertProps {
message?: ReactNode;
actions?: ReactNode;
className?: string;
severity: "success" | "warning" | "error";
severity: "success" | "warning" | "error" | "info";
}
export function Alert(props: AlertProps) {
const { severity } = props;
@ -19,6 +19,7 @@ export function Alert(props: AlertProps) {
props.className,
severity === "error" && "border-red-900 bg-red-50 text-red-800",
severity === "warning" && "border-yellow-700 bg-yellow-50 text-yellow-700",
severity === "info" && "border-sky-700 bg-sky-50 text-sky-700",
severity === "success" && "bg-gray-900 text-white"
)}>
<div className="flex">
@ -27,7 +28,10 @@ export function Alert(props: AlertProps) {
<XCircleIcon className={classNames("h-5 w-5 text-red-400")} aria-hidden="true" />
)}
{severity === "warning" && (
<InformationCircleIcon className={classNames("h-5 w-5 text-yellow-400")} aria-hidden="true" />
<ExclamationIcon className={classNames("h-5 w-5 text-yellow-400")} aria-hidden="true" />
)}
{severity === "info" && (
<InformationCircleIcon className={classNames("h-5 w-5 text-sky-400")} aria-hidden="true" />
)}
{severity === "success" && (
<CheckCircleIcon className={classNames("h-5 w-5 text-gray-400")} aria-hidden="true" />

View File

@ -0,0 +1,33 @@
import { PencilIcon } from "@heroicons/react/solid";
import { useState } from "react";
const EditableHeading = ({ title }: { title: string }) => {
const [editIcon, setEditIcon] = useState(true);
return (
<div className="group relative cursor-pointer" onClick={() => setEditIcon(false)}>
{editIcon ? (
<>
<h1
style={{ fontSize: 22, letterSpacing: "-0.0009em" }}
className="inline pl-0 text-gray-900 focus:text-black group-hover:text-gray-500">
{title}
</h1>
<PencilIcon className="ml-1 -mt-1 inline h-4 w-4 text-gray-700 group-hover:text-gray-500" />
</>
) : (
<div style={{ marginBottom: -11 }}>
<input
type="text"
autoFocus
style={{ top: -6, fontSize: 22 }}
required
className="relative h-10 w-full cursor-pointer border-none bg-transparent pl-0 text-gray-900 hover:text-gray-700 focus:text-black focus:outline-none focus:ring-0"
defaultValue={title}
/>
</div>
)}
</div>
);
};
export default EditableHeading;

View File

@ -1,8 +1,12 @@
import { PencilIcon } from "@heroicons/react/solid";
import { useRouter } from "next/router";
import { useState } from "react";
import { useForm } from "react-hook-form";
import TimezoneSelect, { ITimezoneOption } from "react-timezone-select";
import { QueryCell } from "@lib/QueryCell";
import { DEFAULT_SCHEDULE } from "@lib/availability";
import { HttpError } from "@lib/core/http/error";
import { useLocale } from "@lib/hooks/useLocale";
import showToast from "@lib/notification";
import { inferQueryOutput, trpc } from "@lib/trpc";
@ -12,6 +16,7 @@ import Shell from "@components/Shell";
import Schedule from "@components/availability/Schedule";
import { Form } from "@components/form/fields";
import Button from "@components/ui/Button";
import EditableHeading from "@components/ui/EditableHeading";
import Switch from "@components/ui/Switch";
type FormValues = {
@ -20,23 +25,21 @@ type FormValues = {
export function AvailabilityForm(props: inferQueryOutput<"viewer.availability">) {
const { t } = useLocale();
const [timeZone, setTimeZone] = useState(props.timeZone);
const router = useRouter();
const createSchedule = async ({ schedule }: FormValues) => {
const res = await fetch(`/api/schedule`, {
method: "POST",
body: JSON.stringify({ schedule, timeZone: props.timeZone }),
headers: {
"Content-Type": "application/json",
},
});
if (!res.ok) {
throw new Error((await res.json()).message);
}
const responseData = await res.json();
showToast(t("availability_updated_successfully"), "success");
return responseData.data;
};
const updateMutation = trpc.useMutation("viewer.schedule.update", {
onSuccess: async () => {
await router.push("/availability");
showToast(t("availability_updated_successfully"), "success");
},
onError: (err) => {
if (err instanceof HttpError) {
const message = `${err.statusCode}: ${err.message}`;
showToast(message, "error");
}
},
});
const form = useForm({
defaultValues: {
@ -49,7 +52,11 @@ export function AvailabilityForm(props: inferQueryOutput<"viewer.availability">)
<Form
form={form}
handleSubmit={async (values) => {
await createSchedule(values);
updateMutation.mutate({
scheduleId: parseInt(router.query.schedule as string, 10),
schedule: values.schedule,
timeZone: timeZone !== props.timeZone ? timeZone : undefined,
});
}}
className="col-span-3 space-y-2 lg:col-span-2">
<div className="divide-y rounded-sm border border-gray-200 bg-white px-4 py-5 sm:p-6">
@ -63,7 +70,7 @@ export function AvailabilityForm(props: inferQueryOutput<"viewer.availability">)
<Button>{t("save")}</Button>
</div>
</Form>
<div className="min-w-40 col-span-3 ml-2 lg:col-span-1">
<div className="min-w-40 col-span-3 ml-2 space-y-4 lg:col-span-1">
<Switch
defaultChecked={!!props.isDefault}
onCheckedChange={(isChecked) => {
@ -71,6 +78,19 @@ export function AvailabilityForm(props: inferQueryOutput<"viewer.availability">)
}}
label={t("set_to_default")}
/>
<div>
<label htmlFor="timeZone" className="block text-sm font-medium text-gray-700">
{t("timezone")}
</label>
<div className="mt-1">
<TimezoneSelect
id="timeZone"
value={timeZone}
onChange={(tz: ITimezoneOption) => setTimeZone(tz.value)}
className="focus:border-brand mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:ring-black sm:text-sm"
/>
</div>
</div>
<div className="mt-2 rounded-sm border border-gray-200 px-4 py-5 sm:p-6 ">
<h3 className="text-base font-medium leading-6 text-gray-900">
{t("something_doesnt_look_right")}
@ -90,19 +110,25 @@ export function AvailabilityForm(props: inferQueryOutput<"viewer.availability">)
}
export default function Availability() {
const { t } = useLocale();
const router = useRouter();
const query = trpc.useQuery([
"viewer.availability",
{
scheduleId: parseInt(router.query.availability as string),
scheduleId: parseInt(router.query.schedule as string),
},
]);
return (
<div>
<Shell heading={t("availability")} subtitle={t("configure_availability")}>
<QueryCell query={query} success={({ data }) => <AvailabilityForm {...data} />} />
</Shell>
<QueryCell
query={query}
success={({ data }) => {
return (
<Shell heading={<EditableHeading title={data.schedule.name} />}>
<AvailabilityForm {...data} />
</Shell>
);
}}
/>
</div>
);
}

View File

@ -1,13 +1,60 @@
import { Schedule, Availability } from "@prisma/client";
import Link from "next/link";
import React from "react";
import { QueryCell } from "@lib/QueryCell";
import { nameOfDay } from "@lib/core/i18n/weekday";
import { useLocale } from "@lib/hooks/useLocale";
import { inferQueryOutput, trpc } from "@lib/trpc";
import Shell from "@components/Shell";
import Button from "@components/ui/Button";
function scheduleAsString(schedule: Schedule, locale: string) {
const weekSpan = (availability: Availability) => {
const days = availability.days.slice(1).reduce(
(days, day) => {
if (days[days.length - 1].length === 1 && days[days.length - 1][0] === day - 1) {
// append if the range is not complete (but the next day needs adding)
days[days.length - 1].push(day);
} else if (days[days.length - 1][days[days.length - 1].length - 1] === day - 1) {
// range complete, overwrite if the last day directly preceeds the current day
days[days.length - 1] = [days[days.length - 1][0], day];
} else {
// new range
days.push([day]);
}
return days;
},
[[availability.days[0]]] as number[][]
);
return days
.map((dayRange) => dayRange.map((day) => nameOfDay(locale, day, "short")).join(" - "))
.join(", ");
};
const timeSpan = (availability: Availability) => {
return (
new Intl.DateTimeFormat(locale, { hour: "numeric", minute: "numeric" }).format(availability.startTime) +
" - " +
new Intl.DateTimeFormat(locale, { hour: "numeric", minute: "numeric" }).format(availability.endTime)
);
};
return (
<>
{schedule.availability.map((availability: Availability) => (
<>
{weekSpan(availability)}, {timeSpan(availability)}
<br />
</>
))}
</>
);
}
export function AvailabilityList({ schedules }: inferQueryOutput<"viewer.availability.list">) {
const { t } = useLocale();
const { t, i18n } = useLocale();
return (
<div className="-mx-4 mb-16 overflow-hidden rounded-sm border border-gray-200 bg-white sm:mx-0">
<ul className="divide-y divide-neutral-200" data-testid="schedules">
@ -25,6 +72,9 @@ export function AvailabilityList({ schedules }: inferQueryOutput<"viewer.availab
</span>
)}
</div>
<p className="mt-1 text-xs text-neutral-500">
{scheduleAsString(schedule, i18n.language)}
</p>
</a>
</Link>
</div>
@ -36,12 +86,19 @@ export function AvailabilityList({ schedules }: inferQueryOutput<"viewer.availab
);
}
export default function Availability() {
export default function AvailabilityPage() {
const { t } = useLocale();
const query = trpc.useQuery(["viewer.availability.list"]);
return (
<div>
<Shell heading={t("availability")} subtitle={t("configure_availability")}>
<Shell
heading={t("availability")}
subtitle={t("configure_availability")}
CTA={
<Link href="/availability/9">
<Button>New schedule</Button>
</Link>
}>
<QueryCell query={query} success={({ data }) => <AvailabilityList {...data} />} />
</Shell>
</div>

View File

@ -19,6 +19,7 @@ import dayjs from "dayjs";
import timezone from "dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc";
import { GetServerSidePropsContext } from "next";
import Link from "next/link";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
@ -28,6 +29,7 @@ import { JSONObject } from "superjson/dist/types";
import { StripeData } from "@ee/lib/stripe/server";
import { QueryCell } from "@lib/QueryCell";
import { asStringOrThrow, asStringOrUndefined } from "@lib/asStringOrNull";
import { getSession } from "@lib/auth";
import { HttpError } from "@lib/core/http/error";
@ -45,9 +47,9 @@ import Shell from "@components/Shell";
import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent";
import { Form } from "@components/form/fields";
import CustomInputTypeForm from "@components/pages/eventtypes/CustomInputTypeForm";
import { Alert } from "@components/ui/Alert";
import Button from "@components/ui/Button";
import InfoBadge from "@components/ui/InfoBadge";
import { Scheduler } from "@components/ui/Scheduler";
import Switch from "@components/ui/Switch";
import CheckboxField from "@components/ui/form/CheckboxField";
import CheckedSelect from "@components/ui/form/CheckedSelect";
@ -91,6 +93,37 @@ const addDefaultLocationOptions = (
});
};
const AvailabilitySelect = () => {
const query = trpc.useQuery(["viewer.availability.list"]);
return (
<QueryCell
query={query}
success={({ data }) => {
const defaultSchedule = data.schedules.find((schedule) => schedule.isDefault) as {
id: number;
name: string;
};
return (
<Select
name="schedule"
defaultValue={{
value: defaultSchedule.id,
label: defaultSchedule.name,
}}
options={data.schedules.map((schedule) => ({
value: schedule.id,
label: schedule.name,
}))}
isSearchable={false}
classNamePrefix="react-select"
className="react-select-container focus:border-primary-500 focus:ring-primary-500 block w-full min-w-0 flex-1 rounded-sm border border-gray-300 sm:text-sm"
/>
);
}}
/>
);
};
const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
const { t } = useLocale();
const PERIOD_TYPES = [
@ -1179,29 +1212,19 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
<div className="w-full">
<Controller
name="availability"
name="schedule"
control={formMethods.control}
render={() => (
<Scheduler
setAvailability={(val) => {
formMethods.setValue("availability", {
openingHours: val.openingHours,
dateOverrides: val.dateOverrides,
});
}}
setTimeZone={(timeZone) => {
formMethods.setValue("timeZone", timeZone);
setSelectedTimeZone(timeZone);
}}
timeZone={selectedTimeZone}
availability={availability.map((schedule) => ({
...schedule,
startTime: new Date(schedule.startTime),
endTime: new Date(schedule.endTime),
}))}
/>
)}
render={() => <AvailabilitySelect />}
/>
<Link href="/availability">
<a>
<Alert
className="mt-1 text-xs"
severity="info"
message="You can manage your schedules on the Availability page."
/>
</a>
</Link>
</div>
</div>

View File

@ -658,5 +658,6 @@
"error_404": "Error 404",
"set_to_default": "Set to Default",
"requires_ownership_of_a_token": "Requires ownership of a token belonging to the following address:",
"example_name": "John Doe"
"example_name": "John Doe",
"click_to_add_a_new_schedule": "Add a new schedule"
}

View File

@ -520,5 +520,8 @@
"calendar": "Agenda",
"not_installed": "Niet geïnstalleerd",
"error_password_mismatch": "Wachtwoorden komen niet overeen.",
"error_required_field": "Dit veld is verplicht."
"error_required_field": "Dit veld is verplicht.",
"default": "standaard keuze",
"set_to_default": "Zet als standaard keuze",
"click_here_to_add_a_new_schedule": "Klik hier om een nieuwe planning aan te maken"
}

View File

@ -5,6 +5,7 @@ import { z } from "zod";
import { checkPremiumUsername } from "@ee/lib/core/checkPremiumUsername";
import { getAvailabilityFromSchedule } from "@lib/availability";
import { checkRegularUsername } from "@lib/core/checkRegularUsername";
import { getCalendarCredentials, getConnectedCalendars } from "@lib/integrations/calendar/CalendarManager";
import { ALL_INTEGRATIONS } from "@lib/integrations/getIntegrations";
@ -636,6 +637,45 @@ const loggedInViewerRouter = createProtectedRouter()
};
},
})
.mutation("schedule.update", {
input: z.object({
scheduleId: z.number(),
timeZone: z.string().optional(),
schedule: z.array(
z.array(
z.object({
start: z.date(),
end: z.date(),
})
)
),
}),
async resolve({ input, ctx }) {
const { user, prisma } = ctx;
const availability = getAvailabilityFromSchedule(input.schedule);
await prisma.schedule.update({
where: {
id: input.scheduleId,
},
data: {
availability: {
deleteMany: {
scheduleId: {
equals: input.scheduleId,
},
},
createMany: {
data: availability.map((schedule) => ({
days: schedule.days,
startTime: schedule.startTime,
endTime: schedule.endTime,
})),
},
},
},
});
},
})
.mutation("updateProfile", {
input: z.object({
username: z.string().optional(),

View File

@ -38,7 +38,9 @@ export function getAvailabilityFromSchedule(schedule: Schedule): Availability[]
let idx;
if (
(idx = availability.findIndex(
(schedule) => schedule.startTime === time.start && schedule.endTime === time.end
(schedule) =>
schedule.startTime.toString() === time.start.toString() &&
schedule.endTime.toString() === time.end.toString()
)) !== -1
) {
availability[idx].days.push(day);

View File

@ -1,21 +1,22 @@
import * as z from "zod"
import * as imports from "../zod-utils"
import { CompleteUser, UserModel, CompleteEventType, EventTypeModel } from "./index"
import { CompleteUser, UserModel, CompleteEventType, EventTypeModel, CompleteSchedule, ScheduleModel } from "./index"
export const _AvailabilityModel = z.object({
id: z.number().int(),
label: z.string().nullish(),
userId: z.number().int().nullish(),
eventTypeId: z.number().int().nullish(),
days: z.number().int().array(),
startTime: z.date(),
endTime: z.date(),
date: z.date().nullish(),
scheduleId: z.number().int().nullish(),
})
export interface CompleteAvailability extends z.infer<typeof _AvailabilityModel> {
user?: CompleteUser | null
eventType?: CompleteEventType | null
Schedule?: CompleteSchedule | null
}
/**
@ -26,4 +27,5 @@ export interface CompleteAvailability extends z.infer<typeof _AvailabilityModel>
export const AvailabilityModel: z.ZodSchema<CompleteAvailability> = z.lazy(() => _AvailabilityModel.extend({
user: UserModel.nullish(),
eventType: EventTypeModel.nullish(),
Schedule: ScheduleModel.nullish(),
}))

View File

@ -1,17 +0,0 @@
import { _EventTypeModel } from "./eventtype";
const createEventTypeBaseInput = _EventTypeModel
.pick({
title: true,
slug: true,
description: true,
length: true,
teamId: true,
schedulingType: true,
})
.refine((data) => (data.teamId ? data.teamId && data.schedulingType : true), {
path: ["schedulingType"],
message: "You must select a scheduling type for team events",
});
export const createEventTypeInput = createEventTypeBaseInput;

View File

@ -1,24 +1,18 @@
import * as z from "zod"
import * as imports from "../zod-utils"
import { CompleteUser, UserModel, CompleteEventType, EventTypeModel } from "./index"
// Helper schema for JSON fields
type Literal = boolean | number | string
type Json = Literal | { [key: string]: Json } | Json[]
const literalSchema = z.union([z.string(), z.number(), z.boolean()])
const jsonSchema: z.ZodSchema<Json> = z.lazy(() => z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]))
import { CompleteUser, UserModel, CompleteEventType, EventTypeModel, CompleteAvailability, AvailabilityModel } from "./index"
export const _ScheduleModel = z.object({
id: z.number().int(),
userId: z.number().int().nullish(),
userId: z.number().int(),
eventTypeId: z.number().int().nullish(),
title: z.string().nullish(),
freeBusyTimes: jsonSchema,
name: z.string(),
})
export interface CompleteSchedule extends z.infer<typeof _ScheduleModel> {
user?: CompleteUser | null
user: CompleteUser
eventType?: CompleteEventType | null
availability: CompleteAvailability[]
}
/**
@ -27,6 +21,7 @@ export interface CompleteSchedule extends z.infer<typeof _ScheduleModel> {
* NOTE: Lazy required in case of potential circular dependencies within schema
*/
export const ScheduleModel: z.ZodSchema<CompleteSchedule> = z.lazy(() => _ScheduleModel.extend({
user: UserModel.nullish(),
user: UserModel,
eventType: EventTypeModel.nullish(),
availability: AvailabilityModel.array(),
}))

View File

@ -1,7 +1,7 @@
import * as z from "zod"
import * as imports from "../zod-utils"
import { IdentityProvider, UserPlan } from "@prisma/client"
import { CompleteEventType, EventTypeModel, CompleteCredential, CredentialModel, CompleteMembership, MembershipModel, CompleteBooking, BookingModel, CompleteAvailability, AvailabilityModel, CompleteSelectedCalendar, SelectedCalendarModel, CompleteSchedule, ScheduleModel, CompleteWebhook, WebhookModel, CompleteDestinationCalendar, DestinationCalendarModel } from "./index"
import { CompleteEventType, EventTypeModel, CompleteCredential, CredentialModel, CompleteMembership, MembershipModel, CompleteBooking, BookingModel, CompleteSchedule, ScheduleModel, CompleteSelectedCalendar, SelectedCalendarModel, CompleteAvailability, AvailabilityModel, CompleteWebhook, WebhookModel, CompleteDestinationCalendar, DestinationCalendarModel } from "./index"
// Helper schema for JSON fields
type Literal = boolean | number | string
@ -45,9 +45,9 @@ export interface CompleteUser extends z.infer<typeof _UserModel> {
credentials: CompleteCredential[]
teams: CompleteMembership[]
bookings: CompleteBooking[]
availability: CompleteAvailability[]
schedule?: CompleteSchedule | null
selectedCalendars: CompleteSelectedCalendar[]
Schedule: CompleteSchedule[]
availability: CompleteAvailability[]
webhooks: CompleteWebhook[]
destinationCalendar?: CompleteDestinationCalendar | null
}
@ -62,9 +62,9 @@ export const UserModel: z.ZodSchema<CompleteUser> = z.lazy(() => _UserModel.exte
credentials: CredentialModel.array(),
teams: MembershipModel.array(),
bookings: BookingModel.array(),
availability: AvailabilityModel.array(),
schedule: ScheduleModel.nullish(),
selectedCalendars: SelectedCalendarModel.array(),
Schedule: ScheduleModel.array(),
availability: AvailabilityModel.array(),
webhooks: WebhookModel.array(),
destinationCalendar: DestinationCalendarModel.nullish(),
}))

View File

@ -2080,27 +2080,40 @@
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-dialog@^0.1.0":
version "0.1.5"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-0.1.5.tgz#4310659607f5ad0b8796623d5f7490dc47d3d295"
integrity sha512-WftvXcQSszUphCTLQkkpBIkrYYU0IYqgIvACLQady4BN4YHDgdNlrwdg2ti9QrXgq1PZ+0S/6BIaA1dmSuRQ2g==
"@radix-ui/react-dialog@0.1.4":
version "0.1.4"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-0.1.4.tgz#c2ac74abfe8404dbf7582a439c4e8c39ff569f3a"
integrity sha512-EENTf+WVtRv4zhYf6Lddd0he/HBUMp19T4J1YyYdN1uw/yOlRVx73etxa1GvQYsiVx1aE5DJ8C3lNLSWlZ0fag==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "0.1.0"
"@radix-ui/react-compose-refs" "0.1.0"
"@radix-ui/react-context" "0.1.1"
"@radix-ui/react-dismissable-layer" "0.1.3"
"@radix-ui/react-dismissable-layer" "0.1.2"
"@radix-ui/react-focus-guards" "0.1.0"
"@radix-ui/react-focus-scope" "0.1.3"
"@radix-ui/react-id" "0.1.4"
"@radix-ui/react-portal" "0.1.3"
"@radix-ui/react-focus-scope" "0.1.2"
"@radix-ui/react-id" "0.1.3"
"@radix-ui/react-portal" "0.1.2"
"@radix-ui/react-presence" "0.1.1"
"@radix-ui/react-primitive" "0.1.3"
"@radix-ui/react-primitive" "0.1.2"
"@radix-ui/react-slot" "0.1.2"
"@radix-ui/react-use-controllable-state" "0.1.0"
aria-hidden "^1.1.1"
react-remove-scroll "^2.4.0"
"@radix-ui/react-dismissable-layer@0.1.2":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.2.tgz#10192ca6f28f1add825445afdfc23798cfd9342e"
integrity sha512-qQ8lK2PW8P3qEjJw3cKauwPNOZ2eaIffp9/WDOh0BjKg0YOf3RdLB3BuFwfULs5avo5rC4u85D0NQuw0IsPplQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "0.1.0"
"@radix-ui/react-context" "0.1.1"
"@radix-ui/react-primitive" "0.1.2"
"@radix-ui/react-use-body-pointer-events" "0.1.0"
"@radix-ui/react-use-callback-ref" "0.1.0"
"@radix-ui/react-use-escape-keydown" "0.1.0"
"@radix-ui/react-dismissable-layer@0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.3.tgz#d427c7520c3799d2b957e40e7d67045d96120356"
@ -2135,6 +2148,16 @@
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-focus-scope@0.1.2":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.2.tgz#a25da04a5e3ccccc34707837153a5dcb957e86fb"
integrity sha512-oYtrTi5in6YWf2H6PEzpHu9upFZXJ1GDmWAZ3TE78d2YBstCykKNTRX/pAmNonxI8Men607eKNbVBHPROjprhA==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "0.1.0"
"@radix-ui/react-primitive" "0.1.2"
"@radix-ui/react-use-callback-ref" "0.1.0"
"@radix-ui/react-focus-scope@0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.3.tgz#b1cc825b6190001d731417ed90d192d13b41bce1"
@ -2145,6 +2168,14 @@
"@radix-ui/react-primitive" "0.1.3"
"@radix-ui/react-use-callback-ref" "0.1.0"
"@radix-ui/react-id@0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.1.3.tgz#007c41749628ec6c2c801ad0b8f0a454bb181ae3"
integrity sha512-kA7erDg8S/bad9O6RTC+laW11gm2pvmEqlZA+rvzI+WEkQXStIgnVp+wA420be4q20UiLQw9cmIP01AIhDVdZQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-use-layout-effect" "0.1.0"
"@radix-ui/react-id@0.1.4", "@radix-ui/react-id@^0.1.0":
version "0.1.4"
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.1.4.tgz#4cd6126e6ac8a43ebe6d52948a068b797cc9ad71"
@ -2203,6 +2234,15 @@
"@radix-ui/react-use-size" "0.1.0"
"@radix-ui/rect" "0.1.1"
"@radix-ui/react-portal@0.1.2":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-0.1.2.tgz#a47059fe04ead0749d879818a7cbe9e7c751c4d5"
integrity sha512-rLSe5aeJ7yWD6CuUyg+U9wCoMLleRyxQS67eqALzLW7zk0glB5q5x2ihAEjocZH2Tng9v5QkYaLyh2+sO3TMRA==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "0.1.2"
"@radix-ui/react-use-layout-effect" "0.1.0"
"@radix-ui/react-portal@0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-0.1.3.tgz#56826e789b3d4e37983f6d23666e3f1b1b9ee358"
@ -2221,6 +2261,14 @@
"@radix-ui/react-compose-refs" "0.1.0"
"@radix-ui/react-use-layout-effect" "0.1.0"
"@radix-ui/react-primitive@0.1.2":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-0.1.2.tgz#ca20fb15fc83124eead186333f917145e5e53378"
integrity sha512-mVgeBkuNRZRCzHuDm2DWjZEIs3ntp4m3GtKWPXUn+SgmJXIIpVLt7KhvEmNkgXURq/DJgxG9GmJJMXkACioH/A==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-slot" "0.1.2"
"@radix-ui/react-primitive@0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-0.1.3.tgz#585c35ef2ec06bab0ea9e0fc5c916e556661b881"