Merge branch 'main' of http://git.sepehrdata.com/Saeed0920/inogen
This commit is contained in:
commit
f1b4d313eb
|
|
@ -441,12 +441,37 @@ export function DigitalInnovationPage() {
|
|||
innovation_digital_function: {},
|
||||
});
|
||||
|
||||
let payload: DigitalInnovationMetrics = raw?.data;
|
||||
if (typeof payload === "string") {
|
||||
|
||||
|
||||
// let payload: DigitalInnovationMetrics = raw?.data;
|
||||
// console.log("*-*-*-*" +payload);
|
||||
// if (typeof payload === "string") {
|
||||
// try {
|
||||
// payload = JSON.parse(payload).innovation_digital_function;
|
||||
|
||||
// } catch {}
|
||||
// }
|
||||
|
||||
let payload: DigitalInnovationMetrics | null = null;
|
||||
|
||||
if (raw?.data) {
|
||||
try {
|
||||
payload = JSON.parse(payload);
|
||||
} catch {}
|
||||
// مرحله اول: data رو از string به object تبدیل کن
|
||||
const parsedData = JSON.parse(raw.data);
|
||||
|
||||
// مرحله دوم: innovation_digital_function رو که خودش string هست parse کن
|
||||
const arr = JSON.parse(parsedData.innovation_digital_function);
|
||||
|
||||
// مرحله سوم: اولین خانه آرایه رو بردار
|
||||
if (Array.isArray(arr) && arr.length > 0) {
|
||||
payload = arr[0];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error parsing API response:", err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const parseNum = (v: unknown): number => {
|
||||
if (v == null) return 0;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import moment from "moment-jalaali";
|
||||
// import moment from "moment-jalaali";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
Bar,
|
||||
|
|
@ -47,7 +47,7 @@ import apiService from "~/lib/api";
|
|||
import { formatCurrency } from "~/lib/utils";
|
||||
import DashboardLayout from "../layout";
|
||||
|
||||
moment.loadPersian({ usePersianDigits: true });
|
||||
// moment.loadPersian({ usePersianDigits: true });
|
||||
interface GreenInnovationData {
|
||||
WorkflowID: string;
|
||||
approved_budget: string;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import moment from "moment-jalaali";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Badge } from "~/components/ui/badge";
|
||||
import { Button } from "~/components/ui/button";
|
||||
|
|
@ -43,8 +42,6 @@ import apiService from "~/lib/api";
|
|||
import { formatCurrency } from "~/lib/utils";
|
||||
import DashboardLayout from "../layout";
|
||||
|
||||
moment.loadPersian({ usePersianDigits: true });
|
||||
|
||||
interface innovationBuiltInDate {
|
||||
WorkflowID: number;
|
||||
approved_budget: string;
|
||||
|
|
@ -194,9 +191,8 @@ export function InnovationBuiltInsidePage() {
|
|||
direction: "asc",
|
||||
});
|
||||
const [tblAvarage, setTblAvarage] = useState<number>(0);
|
||||
const [selectedProjects, setSelectedProjects] = useState<
|
||||
Set<string | number>
|
||||
>(new Set());
|
||||
const [selectedProjects, setSelectedProjects] =
|
||||
useState<Set<string | number>>();
|
||||
const [detailsDialogOpen, setDetailsDialogOpen] = useState(false);
|
||||
const [selectedProjectDetails, setSelectedProjectDetails] =
|
||||
useState<DialogInfo>();
|
||||
|
|
@ -426,7 +422,6 @@ export function InnovationBuiltInsidePage() {
|
|||
|
||||
useEffect(() => {
|
||||
fetchProjects(true);
|
||||
fetchStats();
|
||||
}, [sortConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -486,7 +481,7 @@ export function InnovationBuiltInsidePage() {
|
|||
const raw = await apiService.call<any>({
|
||||
innovation_construction_inside_function: {
|
||||
project_ids:
|
||||
selectedProjects.size > 0
|
||||
selectedProjects && selectedProjects?.size > 0
|
||||
? Array.from(selectedProjects).join(" , ")
|
||||
: "",
|
||||
},
|
||||
|
|
@ -622,7 +617,7 @@ export function InnovationBuiltInsidePage() {
|
|||
case "select":
|
||||
return (
|
||||
<Checkbox
|
||||
checked={selectedProjects.has(item?.project_id!)}
|
||||
checked={selectedProjects?.has(item?.project_id!)}
|
||||
onCheckedChange={() => handleSelectProject(item?.project_id)}
|
||||
className="data-[state=checked]:bg-emerald-600 data-[state=checked]:border-emerald-600 cursor-pointer"
|
||||
/>
|
||||
|
|
@ -1039,7 +1034,7 @@ export function InnovationBuiltInsidePage() {
|
|||
|
||||
{/* Project Details Dialog */}
|
||||
<Dialog open={detailsDialogOpen} onOpenChange={setDetailsDialogOpen}>
|
||||
<DialogContent className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] max-w-5xl overflow-y-auto">
|
||||
<DialogContent className="bg-[linear-gradient(to_bottom_left,#464861,50%,#111628)] max-w-6xl overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-white mr-4 border-b-2 border-gray-600 pb-4 font-persian text-right">
|
||||
شرح پروژه
|
||||
|
|
@ -1192,12 +1187,12 @@ export function InnovationBuiltInsidePage() {
|
|||
</div>
|
||||
) : (
|
||||
<div className="tbl rounded-xl overflow-hidden">
|
||||
<div className="grid grid-cols-3 bg-[#3F415A] text-white">
|
||||
<span className="text-md text-center p-3">
|
||||
<div className="grid grid-cols-3 bg-[#3F415A] text-white p-3 items-center">
|
||||
<span className="text-md text-center">
|
||||
شاخص مقایسه با نمونه خارجی
|
||||
</span>
|
||||
<span className="text-md text-center p-3">نمونه داخلی</span>
|
||||
<span className="text-md text-center p-3">نمونه خارجی</span>
|
||||
<span className="text-md text-center">نمونه داخلی</span>
|
||||
<span className="text-md text-center">نمونه خارجی</span>
|
||||
</div>
|
||||
<div className="flex flex-col divide-y divide-gray-600 overflow-auto max-h-[6rem]">
|
||||
{selectedProjectDetails?.technology_params?.map(
|
||||
|
|
@ -1268,7 +1263,7 @@ export function InnovationBuiltInsidePage() {
|
|||
<ResponsiveContainer width="100%" height={420}>
|
||||
<LineChart
|
||||
data={dialogChartData}
|
||||
margin={{ top: 20, right: 20, left: 20, bottom: 80 }}
|
||||
margin={{ top: 20, right: 70, left: 30, bottom: 80 }}
|
||||
>
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
|
|
@ -1323,7 +1318,7 @@ export function InnovationBuiltInsidePage() {
|
|||
axisOffsetX -
|
||||
15;
|
||||
|
||||
const rectWidth = 140;
|
||||
const rectWidth = 130;
|
||||
const rectHeight = 28;
|
||||
const rectX = x - rectWidth / 2;
|
||||
const axisHeight = xAxis?.height ?? 40;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -219,12 +219,7 @@ export function Sidebar({
|
|||
if (item.id === "strategic-alignment") {
|
||||
return (
|
||||
<button
|
||||
className={cn(
|
||||
"w-full text-right",
|
||||
)}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div
|
||||
key={item.id}
|
||||
className={cn(
|
||||
"flex items-center justify-center w-full px-2 rounded-lg mt-4 transition-all duration-200 group",
|
||||
)}
|
||||
|
|
@ -234,7 +229,6 @@ export function Sidebar({
|
|||
{item.label}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
|
||||
|
|
|
|||
39
app/components/ui/funnel-chart.test.tsx
Normal file
39
app/components/ui/funnel-chart.test.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { FunnelChart } from './funnel-chart';
|
||||
|
||||
const mockData = [
|
||||
{ name: "تعداد کل", value: 250, label: "تعداد کل" },
|
||||
{ name: "نمونه موفق", value: 130, label: "نمونه موفق" },
|
||||
{ name: "محصولات موفق", value: 70, label: "محصولات موفق" },
|
||||
{ name: "بهبود یا تغییر موفق", value: 80, label: "بهبود یا تغییر موفق" },
|
||||
{ name: "محصول جدید", value: 50, label: "محصول جدید" },
|
||||
];
|
||||
|
||||
describe('FunnelChart', () => {
|
||||
it('renders funnel chart with correct data', () => {
|
||||
render(<FunnelChart data={mockData} title="قيف فرآیند پروژه ها" />);
|
||||
|
||||
expect(screen.getByText('قيف فرآیند پروژه ها')).toBeInTheDocument();
|
||||
expect(screen.getByText('۱۰۰%')).toBeInTheDocument();
|
||||
expect(screen.getByText('۲۵%')).toBeInTheDocument();
|
||||
expect(screen.getByText('ابتدا فرآیند')).toBeInTheDocument();
|
||||
expect(screen.getByText('انتها فرآیند')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays funnel data values correctly', () => {
|
||||
render(<FunnelChart data={mockData} />);
|
||||
|
||||
expect(screen.getByText('۲۵۰')).toBeInTheDocument();
|
||||
expect(screen.getByText('۱۳۰')).toBeInTheDocument();
|
||||
expect(screen.getByText('۷۰')).toBeInTheDocument();
|
||||
expect(screen.getByText('۸۰')).toBeInTheDocument();
|
||||
expect(screen.getByText('۵۰')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders without title when not provided', () => {
|
||||
render(<FunnelChart data={mockData} />);
|
||||
|
||||
expect(screen.queryByText('قيف فرآیند پروژه ها')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
95
app/components/ui/funnel-chart.tsx
Normal file
95
app/components/ui/funnel-chart.tsx
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import React from "react";
|
||||
import { formatNumber } from "~/lib/utils";
|
||||
|
||||
interface FunnelData {
|
||||
name: string;
|
||||
value: number;
|
||||
label: string;
|
||||
percentage?: string;
|
||||
}
|
||||
|
||||
interface FunnelChartProps {
|
||||
data: FunnelData[];
|
||||
title?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function FunnelChart({ data, title, className = "" }: FunnelChartProps) {
|
||||
const maxValue = Math.max(...data.map(d => d.value));
|
||||
const toPercent = (value: number) => {
|
||||
if (!maxValue || maxValue <= 0) return 0;
|
||||
return Math.round((value / maxValue) * 100);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`w-full ${className}`}>
|
||||
{title && (
|
||||
<h3 className="text-lg font-semibold text-white mb-4 py-2 text-right border-b-2 border-gray-400/20">
|
||||
{title}
|
||||
</h3>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col items-center gap-2 space-y-2">
|
||||
{/* Start Process Line */}
|
||||
<div className="flex items-center w-full gap-10 mt-6">
|
||||
<div className="text-lg text-gray-600 min-w-[max-content]">ابتدا فرآیند</div>
|
||||
<div className="flex items-center w-full gap-4">
|
||||
<div className="w-full h-0.5 bg-gray-600 relative">
|
||||
<div className="text-2xl text-white absolute left-1/2 -translate-x-1/2 top-[-1rem] -translate-y-1/2">۱۰۰%</div>
|
||||
<div className="absolute -top-1 left-0 w-1 h-3 bg-gray-600"></div>
|
||||
<div className="absolute -top-1 right-0 w-1 h-3 bg-gray-600"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Funnel Bars */}
|
||||
<div className="flex flex-col items-center space-y-1 gap-2 w-full max-w-md">
|
||||
{data.map((item, index) => {
|
||||
const widthPercentage = toPercent(item.value);
|
||||
const barWidth = Math.max(20, widthPercentage); // Minimum 20% width
|
||||
|
||||
return (
|
||||
<div key={index} className="grid grid-cols-[6rem_1fr] gap-2 w-full">
|
||||
<div className="text-lg text-white cols-start-1 justify-self-start font-thin min-w-[max-content] text-center">
|
||||
{item.label}
|
||||
</div>
|
||||
<div className="flex items-center gap-10 w-full cols-start-2 flex items-center justify-center w-full">
|
||||
<div className="flex items-center w-full">
|
||||
<div style={{ width: `${(100 - barWidth) / 2}%` }} />
|
||||
<div
|
||||
className="bg-[#3BC47A] h-8 rounded-2xl flex items-center justify-center text-lg relative"
|
||||
style={{ width: `${barWidth}%` }}
|
||||
>
|
||||
<span className="text-[#3F415A] font-semibold">
|
||||
{item.value.toLocaleString('fa-IR')}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ width: `${(100 - barWidth) / 2}%` }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* End Process Line */}
|
||||
<div className="flex items-center w-full gap-10">
|
||||
<div className="text-lg text-gray-600 min-w-[max-content]">انتها فرآیند</div>
|
||||
<div className="flex items-center w-full gap-4">
|
||||
{(() => {
|
||||
const lastValue = data[data.length - 1]?.value ?? 0;
|
||||
const percent = toPercent(lastValue);
|
||||
return (
|
||||
<div style={{ width: `${percent}%` }} className={`mx-auto h-0.5 bg-gray-600 relative ${percent === 0 ? "hidden" : ""}`}>
|
||||
<div className="text-2xl text-white absolute left-1/2 -translate-x-1/2 bottom-[-2.5rem] -translate-y-1">{formatNumber(percent)}%</div>
|
||||
<div className="absolute -top-1 left-0 w-1 h-3 bg-gray-600"></div>
|
||||
<div className="absolute -top-1 right-0 w-1 h-3 bg-gray-600"></div>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
48
app/components/ui/popover.tsx
Normal file
48
app/components/ui/popover.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||
|
||||
import { cn } from "~/lib/utils"
|
||||
|
||||
function Popover({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
||||
return <PopoverPrimitive.Root data-slot="popover" {...props} />
|
||||
}
|
||||
|
||||
function PopoverTrigger({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
||||
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
|
||||
}
|
||||
|
||||
function PopoverContent({
|
||||
className,
|
||||
align = "center",
|
||||
sideOffset = 4,
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
|
||||
return (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
data-slot="popover-content"
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground 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 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverAnchor({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
|
||||
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
|
||||
}
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import moment from "moment-jalaali";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
|
|
@ -20,3 +21,23 @@ export const formatCurrency = (amount: string | number) => {
|
|||
if (isNaN(numericAmount)) return "0 ریال";
|
||||
return new Intl.NumberFormat("fa-IR").format(numericAmount) + " ریال";
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const handleDataValue = (val: any): any => {
|
||||
moment.loadPersian({ usePersianDigits: true });
|
||||
if (val == null) return val;
|
||||
if (
|
||||
typeof val === "string" &&
|
||||
/^\d{4}[-/]\d{2}[-/]\d{2}( \d{2}:\d{2}(:\d{2})?)?$/.test(val)
|
||||
) {
|
||||
return moment(val, "YYYY-MM-DD HH:mm:ss").format("YYYY/MM/DD");
|
||||
}
|
||||
if (
|
||||
typeof val === "number" ||
|
||||
(typeof val === "string" && /^-?\d+$/.test(val))
|
||||
) {
|
||||
return val.toString().replace(/\d/g, (d) => "۰۱۲۳۴۵۶۷۸۹"[+d]);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ export default [
|
|||
route(
|
||||
"dashboard/innovation-basket/process-innovation",
|
||||
"routes/innovation-basket.process-innovation.tsx"
|
||||
),
|
||||
route(
|
||||
"dashboard/innovation-basket/product-innovation",
|
||||
"routes/innovation-basket.product-innovation.tsx"
|
||||
),
|
||||
route(
|
||||
"dashboard/innovation-basket/green-innovation",
|
||||
|
|
|
|||
17
app/routes/innovation-basket.product-innovation.tsx
Normal file
17
app/routes/innovation-basket.product-innovation.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { ProductInnovationPage } from "~/components/dashboard/project-management/product-innovation-page";
|
||||
import { ProtectedRoute } from "~/components/auth/protected-route";
|
||||
|
||||
export function meta() {
|
||||
return [
|
||||
{ title: "نوآوری محصول - سیستم مدیریت فناوری و نوآوری" },
|
||||
{ name: "description", content: "مدیریت پروژههای نوآوری محصول" },
|
||||
];
|
||||
}
|
||||
|
||||
export default function ProductInnovation() {
|
||||
return (
|
||||
<ProtectedRoute requireAuth={true}>
|
||||
<ProductInnovationPage />
|
||||
</ProtectedRoute>
|
||||
);
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
"@radix-ui/react-dialog": "^1.1.14",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
"@radix-ui/react-popover": "^1.1.15",
|
||||
"@radix-ui/react-progress": "^1.1.7",
|
||||
"@radix-ui/react-select": "^2.2.5",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ importers:
|
|||
'@radix-ui/react-label':
|
||||
specifier: ^2.0.2
|
||||
version: 2.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-popover':
|
||||
specifier: ^1.1.15
|
||||
version: 1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-progress':
|
||||
specifier: ^1.1.7
|
||||
version: 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
|
|
@ -645,6 +648,19 @@ packages:
|
|||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-popover@1.1.15':
|
||||
resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-popper@1.2.8':
|
||||
resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==}
|
||||
peerDependencies:
|
||||
|
|
@ -3009,6 +3025,29 @@ snapshots:
|
|||
'@types/react': 19.1.12
|
||||
'@types/react-dom': 19.1.9(@types/react@19.1.12)
|
||||
|
||||
'@radix-ui/react-popover@1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.1)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.1)
|
||||
'@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.12)(react@19.1.1)
|
||||
'@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.1)
|
||||
'@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.1)
|
||||
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.1)
|
||||
aria-hidden: 1.2.6
|
||||
react: 19.1.1
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
react-remove-scroll: 2.7.1(@types/react@19.1.12)(react@19.1.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.12
|
||||
'@types/react-dom': 19.1.9(@types/react@19.1.12)
|
||||
|
||||
'@radix-ui/react-popper@1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@floating-ui/react-dom': 2.1.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user