feat: add pagination size selection and compact view toggle in series grid
This commit is contained in:
12
docs/api.md
12
docs/api.md
@@ -50,6 +50,18 @@
|
||||
- **Description** : Liste des bibliothèques
|
||||
- **Réponse** : `Library[]`
|
||||
|
||||
### GET /libraries/[libraryId]
|
||||
|
||||
- **Description** : Page d'une bibliothèque
|
||||
- **Paramètres** : `libraryId` dans l'URL
|
||||
- **Query Parameters** :
|
||||
- `page` : Numéro de page (défaut: 1)
|
||||
- `size` : Nombre d'éléments par page (défaut: 20, valeurs possibles: 20, 50, 100)
|
||||
- `unread` : Filtrer les séries non lues (défaut: false)
|
||||
- `search` : Rechercher une série par titre
|
||||
- `compact` : Mode d'affichage compact (défaut: false)
|
||||
- **Réponse** : Page HTML avec la liste des séries
|
||||
|
||||
## 📖 Séries
|
||||
|
||||
### GET /api/komga/series/[seriesId]
|
||||
|
||||
@@ -35,9 +35,14 @@ Service de gestion des bibliothèques
|
||||
- Récupère une bibliothèque spécifique
|
||||
- Lance une erreur si non trouvée
|
||||
|
||||
- `getLibrarySeries(libraryId: string, page: number = 0, size: number = 20, unreadOnly: boolean = false): Promise<LibraryResponse<Series>>`
|
||||
- `getLibrarySeries(libraryId: string, page: number = 0, size: number = 20, unreadOnly: boolean = false, search?: string): Promise<LibraryResponse<Series>>`
|
||||
- Récupère les séries d'une bibliothèque
|
||||
- Supporte la pagination et le filtrage
|
||||
- Paramètres :
|
||||
- `page` : Numéro de page (défaut: 0)
|
||||
- `size` : Nombre d'éléments par page (défaut: 20, valeurs possibles: 20, 50, 100)
|
||||
- `unreadOnly` : Filtrer les séries non lues (défaut: false)
|
||||
- `search` : Rechercher une série par titre (optionnel)
|
||||
|
||||
## 📖 SeriesService
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"@radix-ui/react-dialog": "1.0.5",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||
"@radix-ui/react-progress": "^1.1.2",
|
||||
"@radix-ui/react-select": "^2.1.6",
|
||||
"@radix-ui/react-slot": "1.0.2",
|
||||
"@radix-ui/react-toast": "1.1.5",
|
||||
"@types/bcrypt": "^5.0.2",
|
||||
|
||||
@@ -13,10 +13,10 @@ import { AppError } from "@/utils/errors";
|
||||
|
||||
interface PageProps {
|
||||
params: { libraryId: string };
|
||||
searchParams: { page?: string; unread?: string; search?: string };
|
||||
searchParams: { page?: string; unread?: string; search?: string; size?: string };
|
||||
}
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
const DEFAULT_PAGE_SIZE = 20;
|
||||
|
||||
async function refreshLibrary(libraryId: string) {
|
||||
"use server";
|
||||
@@ -36,7 +36,8 @@ async function getLibrarySeries(
|
||||
libraryId: string,
|
||||
page: number = 1,
|
||||
unreadOnly: boolean = false,
|
||||
search?: string
|
||||
search?: string,
|
||||
size: number = DEFAULT_PAGE_SIZE
|
||||
) {
|
||||
try {
|
||||
const pageIndex = page - 1;
|
||||
@@ -44,7 +45,7 @@ async function getLibrarySeries(
|
||||
const series: LibraryResponse<KomgaSeries> = await LibraryService.getLibrarySeries(
|
||||
libraryId,
|
||||
pageIndex,
|
||||
PAGE_SIZE,
|
||||
size,
|
||||
unreadOnly,
|
||||
search
|
||||
);
|
||||
@@ -61,16 +62,18 @@ async function LibraryPage({ params, searchParams }: PageProps) {
|
||||
const unread = (await searchParams).unread;
|
||||
const search = (await searchParams).search;
|
||||
const page = (await searchParams).page;
|
||||
const size = (await searchParams).size;
|
||||
|
||||
const currentPage = page ? parseInt(page) : 1;
|
||||
const pageSize = size ? parseInt(size) : DEFAULT_PAGE_SIZE;
|
||||
const preferences: UserPreferences = await PreferencesService.getPreferences();
|
||||
|
||||
// Utiliser le paramètre d'URL s'il existe, sinon utiliser la préférence utilisateur
|
||||
const unreadOnly = unread !== undefined ? unread === "true" : preferences.showOnlyUnread;
|
||||
|
||||
console.log(unreadOnly);
|
||||
try {
|
||||
const { data: series, library }: { data: LibraryResponse<KomgaSeries>; library: KomgaLibrary } =
|
||||
await getLibrarySeries(libraryId, currentPage, unreadOnly, search);
|
||||
await getLibrarySeries(libraryId, currentPage, unreadOnly, search, pageSize);
|
||||
|
||||
return (
|
||||
<div className="container py-8 space-y-8">
|
||||
@@ -90,7 +93,7 @@ async function LibraryPage({ params, searchParams }: PageProps) {
|
||||
currentPage={currentPage}
|
||||
totalPages={series.totalPages}
|
||||
totalElements={series.totalElements}
|
||||
pageSize={PAGE_SIZE}
|
||||
pageSize={pageSize}
|
||||
defaultShowOnlyUnread={preferences.showOnlyUnread}
|
||||
showOnlyUnread={unreadOnly}
|
||||
/>
|
||||
|
||||
@@ -4,11 +4,18 @@ import { SeriesGrid } from "./SeriesGrid";
|
||||
import { Pagination } from "@/components/ui/Pagination";
|
||||
import { useRouter, usePathname, useSearchParams } from "next/navigation";
|
||||
import { useState, useEffect } from "react";
|
||||
import { Loader2, Filter } from "lucide-react";
|
||||
import { Loader2, Filter, LayoutGrid, LayoutList, LayoutTemplate } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { KomgaSeries } from "@/types/komga";
|
||||
import { SearchInput } from "./SearchInput";
|
||||
import { useTranslate } from "@/hooks/useTranslate";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
interface PaginatedSeriesGridProps {
|
||||
series: KomgaSeries[];
|
||||
@@ -34,8 +41,25 @@ export function PaginatedSeriesGrid({
|
||||
const searchParams = useSearchParams();
|
||||
const [isChangingPage, setIsChangingPage] = useState(false);
|
||||
const [showOnlyUnread, setShowOnlyUnread] = useState(initialShowOnlyUnread);
|
||||
const [isCompact, setIsCompact] = useState(searchParams.get("compact") === "true");
|
||||
const { t } = useTranslate();
|
||||
|
||||
const updateUrlParams = async (updates: Record<string, string | null>) => {
|
||||
setIsChangingPage(true);
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
|
||||
// Mettre à jour les paramètres
|
||||
Object.entries(updates).forEach(([key, value]) => {
|
||||
if (value === null) {
|
||||
params.delete(key);
|
||||
} else {
|
||||
params.set(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
await router.push(`${pathname}?${params.toString()}`);
|
||||
};
|
||||
|
||||
// Reset loading state when series change
|
||||
useEffect(() => {
|
||||
setIsChangingPage(false);
|
||||
@@ -49,31 +73,39 @@ export function PaginatedSeriesGrid({
|
||||
// Apply default filter on initial load
|
||||
useEffect(() => {
|
||||
if (defaultShowOnlyUnread && !searchParams.has("unread")) {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set("page", "1");
|
||||
params.set("unread", "true");
|
||||
router.push(`${pathname}?${params.toString()}`);
|
||||
updateUrlParams({ page: "1", unread: "true" });
|
||||
}
|
||||
}, [defaultShowOnlyUnread, pathname, router, searchParams]);
|
||||
|
||||
const handlePageChange = async (page: number) => {
|
||||
setIsChangingPage(true);
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set("page", page.toString());
|
||||
params.set("unread", showOnlyUnread.toString());
|
||||
await router.push(`${pathname}?${params.toString()}`);
|
||||
await updateUrlParams({ page: page.toString(), compact: isCompact.toString() });
|
||||
};
|
||||
|
||||
const handleUnreadFilter = async () => {
|
||||
setIsChangingPage(true);
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set("page", "1");
|
||||
|
||||
const newUnreadState = !showOnlyUnread;
|
||||
setShowOnlyUnread(newUnreadState);
|
||||
params.set("unread", newUnreadState.toString());
|
||||
await updateUrlParams({
|
||||
page: "1",
|
||||
unread: newUnreadState ? "true" : "false",
|
||||
compact: isCompact.toString(),
|
||||
});
|
||||
};
|
||||
|
||||
await router.push(`${pathname}?${params.toString()}`);
|
||||
const handleCompactToggle = async () => {
|
||||
const newCompactState = !isCompact;
|
||||
setIsCompact(newCompactState);
|
||||
await updateUrlParams({
|
||||
page: "1",
|
||||
compact: newCompactState.toString(),
|
||||
});
|
||||
};
|
||||
|
||||
const handlePageSizeChange = async (value: string) => {
|
||||
await updateUrlParams({
|
||||
page: "1",
|
||||
size: value,
|
||||
compact: isCompact.toString(),
|
||||
});
|
||||
};
|
||||
|
||||
// Calculate start and end indices for display
|
||||
@@ -92,15 +124,42 @@ export function PaginatedSeriesGrid({
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-center justify-between flex-wrap gap-4">
|
||||
<div className="flex-1">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||||
<div className="w-full sm:w-auto sm:flex-1">
|
||||
<SearchInput placeholder={t("series.filters.search")} />
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="text-sm text-muted-foreground">{getShowingText()}</p>
|
||||
<Select value={pageSize.toString()} onValueChange={handlePageSizeChange}>
|
||||
<SelectTrigger className="w-[80px]">
|
||||
<LayoutList className="h-4 w-4 mr-2" />
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="20">20</SelectItem>
|
||||
<SelectItem value="50">50</SelectItem>
|
||||
<SelectItem value="100">100</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<button
|
||||
onClick={handleCompactToggle}
|
||||
className="inline-flex items-center gap-2 px-2 py-1.5 text-sm font-medium rounded-lg hover:bg-accent hover:text-accent-foreground whitespace-nowrap"
|
||||
>
|
||||
{isCompact ? (
|
||||
<>
|
||||
<LayoutTemplate className="h-4 w-4" />
|
||||
{t("series.filters.normal")}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<LayoutGrid className="h-4 w-4" />
|
||||
{t("series.filters.compact")}
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleUnreadFilter}
|
||||
className="inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-lg hover:bg-accent hover:text-accent-foreground whitespace-nowrap"
|
||||
className="inline-flex items-center gap-2 px-2 py-1.5 text-sm font-medium rounded-lg hover:bg-accent hover:text-accent-foreground whitespace-nowrap"
|
||||
>
|
||||
<Filter className="h-4 w-4" />
|
||||
{showOnlyUnread ? t("series.filters.showAll") : t("series.filters.unread")}
|
||||
@@ -126,7 +185,7 @@ export function PaginatedSeriesGrid({
|
||||
isChangingPage ? "opacity-25" : "opacity-100"
|
||||
)}
|
||||
>
|
||||
<SeriesGrid series={series} />
|
||||
<SeriesGrid series={series} isCompact={isCompact} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useTranslate } from "@/hooks/useTranslate";
|
||||
|
||||
interface SeriesGridProps {
|
||||
series: KomgaSeries[];
|
||||
isCompact?: boolean;
|
||||
}
|
||||
|
||||
// Utility function to get reading status info
|
||||
@@ -42,7 +43,7 @@ const getReadingStatusInfo = (series: KomgaSeries, t: (key: string, options?: an
|
||||
};
|
||||
};
|
||||
|
||||
export function SeriesGrid({ series }: SeriesGridProps) {
|
||||
export function SeriesGrid({ series, isCompact = false }: SeriesGridProps) {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslate();
|
||||
|
||||
@@ -55,14 +56,22 @@ export function SeriesGrid({ series }: SeriesGridProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-5">
|
||||
<div
|
||||
className={cn(
|
||||
"grid gap-4",
|
||||
isCompact
|
||||
? "grid-cols-3 sm:grid-cols-4 lg:grid-cols-6"
|
||||
: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-5"
|
||||
)}
|
||||
>
|
||||
{series.map((series) => (
|
||||
<button
|
||||
key={series.id}
|
||||
onClick={() => router.push(`/series/${series.id}`)}
|
||||
className={cn(
|
||||
"group relative aspect-[2/3] overflow-hidden rounded-lg bg-muted",
|
||||
series.booksCount === series.booksReadCount && "opacity-50"
|
||||
series.booksCount === series.booksReadCount && "opacity-50",
|
||||
isCompact && "aspect-[3/4]"
|
||||
)}
|
||||
>
|
||||
<SeriesCover
|
||||
|
||||
121
src/components/ui/select.tsx
Normal file
121
src/components/ui/select.tsx
Normal file
@@ -0,0 +1,121 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import * as SelectPrimitive from "@radix-ui/react-select";
|
||||
import { Check, ChevronDown } from "lucide-react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const Select = SelectPrimitive.Root;
|
||||
|
||||
const SelectGroup = SelectPrimitive.Group;
|
||||
|
||||
const SelectValue = SelectPrimitive.Value;
|
||||
|
||||
const SelectTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
));
|
||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
||||
|
||||
const SelectContent = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||
>(({ className, children, position = "popper", ...props }, ref) => (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
>
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
));
|
||||
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
||||
|
||||
const SelectLabel = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
||||
|
||||
const SelectItem = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
));
|
||||
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
||||
|
||||
const SelectSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectGroup,
|
||||
SelectValue,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
};
|
||||
@@ -173,10 +173,12 @@
|
||||
"title": "Filters",
|
||||
"showAll": "Show all",
|
||||
"unread": "Unread",
|
||||
"search": "Search series..."
|
||||
"search": "Search series...",
|
||||
"normal": "Normal",
|
||||
"compact": "Compact"
|
||||
},
|
||||
"display": {
|
||||
"showing": "Showing series {start} to {end} of {total}",
|
||||
"showing": "{start}-{end} of {total}",
|
||||
"page": "Page {current} of {total}"
|
||||
},
|
||||
"header": {
|
||||
|
||||
@@ -173,10 +173,12 @@
|
||||
"title": "Filtres",
|
||||
"showAll": "Afficher tout",
|
||||
"unread": "À lire",
|
||||
"search": "Rechercher une série..."
|
||||
"search": "Rechercher une série...",
|
||||
"normal": "Affichage normal",
|
||||
"compact": "Affichage compact"
|
||||
},
|
||||
"display": {
|
||||
"showing": "Affichage des séries {start} à {end} sur {total}",
|
||||
"showing": "{start}-{end} sur {total}",
|
||||
"page": "Page {current} sur {total}"
|
||||
},
|
||||
"header": {
|
||||
|
||||
44
yarn.lock
44
yarn.lock
@@ -486,6 +486,11 @@
|
||||
resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz"
|
||||
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
|
||||
|
||||
"@radix-ui/number@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.1.0.tgz#1e95610461a09cdf8bb05c152e76ca1278d5da46"
|
||||
integrity sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==
|
||||
|
||||
"@radix-ui/primitive@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz"
|
||||
@@ -769,6 +774,33 @@
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
"@radix-ui/react-use-controllable-state" "1.1.0"
|
||||
|
||||
"@radix-ui/react-select@^2.1.6":
|
||||
version "2.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-2.1.6.tgz#79c07cac4de0188e6f7afb2720a87a0405d88849"
|
||||
integrity sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==
|
||||
dependencies:
|
||||
"@radix-ui/number" "1.1.0"
|
||||
"@radix-ui/primitive" "1.1.1"
|
||||
"@radix-ui/react-collection" "1.1.2"
|
||||
"@radix-ui/react-compose-refs" "1.1.1"
|
||||
"@radix-ui/react-context" "1.1.1"
|
||||
"@radix-ui/react-direction" "1.1.0"
|
||||
"@radix-ui/react-dismissable-layer" "1.1.5"
|
||||
"@radix-ui/react-focus-guards" "1.1.1"
|
||||
"@radix-ui/react-focus-scope" "1.1.2"
|
||||
"@radix-ui/react-id" "1.1.0"
|
||||
"@radix-ui/react-popper" "1.2.2"
|
||||
"@radix-ui/react-portal" "1.1.4"
|
||||
"@radix-ui/react-primitive" "2.0.2"
|
||||
"@radix-ui/react-slot" "1.1.2"
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
"@radix-ui/react-use-controllable-state" "1.1.0"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
"@radix-ui/react-use-previous" "1.1.0"
|
||||
"@radix-ui/react-visually-hidden" "1.1.2"
|
||||
aria-hidden "^1.2.4"
|
||||
react-remove-scroll "^2.6.3"
|
||||
|
||||
"@radix-ui/react-slot@1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz"
|
||||
@@ -857,6 +889,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz#3c2c8ce04827b26a39e442ff4888d9212268bd27"
|
||||
integrity sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==
|
||||
|
||||
"@radix-ui/react-use-previous@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz#d4dd37b05520f1d996a384eb469320c2ada8377c"
|
||||
integrity sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==
|
||||
|
||||
"@radix-ui/react-use-rect@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz#13b25b913bd3e3987cc9b073a1a164bb1cf47b88"
|
||||
@@ -879,6 +916,13 @@
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.3"
|
||||
|
||||
"@radix-ui/react-visually-hidden@1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.2.tgz#8f6025507eb5d8b4b3215ebfd2c71a6632323a62"
|
||||
integrity sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==
|
||||
dependencies:
|
||||
"@radix-ui/react-primitive" "2.0.2"
|
||||
|
||||
"@radix-ui/rect@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.0.tgz#f817d1d3265ac5415dadc67edab30ae196696438"
|
||||
|
||||
Reference in New Issue
Block a user