merge: quick/native-select-search-graph — native select, SearchBar, GraphContainer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-03 15:02:49 +02:00
10 changed files with 948 additions and 105 deletions
+2 -3
View File
@@ -1,6 +1,5 @@
import * as React from "react"
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
import { CheckboxIndicator } from "@base-ui/react/checkbox"
import { cn } from "../core/cn"
interface CheckboxProps extends CheckboxPrimitive.Root.Props {
@@ -30,7 +29,7 @@ function Checkbox({ className, label, id, indeterminate, ...props }: CheckboxPro
indeterminate={indeterminate}
{...props}
>
<CheckboxIndicator
<CheckboxPrimitive.Indicator
data-slot="checkbox-indicator"
className="flex items-center justify-center text-current"
>
@@ -60,7 +59,7 @@ function Checkbox({ className, label, id, indeterminate, ...props }: CheckboxPro
<polyline points="20 6 9 17 4 12" />
</svg>
)}
</CheckboxIndicator>
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
{label && (
<label
@@ -0,0 +1,103 @@
---
name: graph_container
kind: component
lang: ts
domain: ui
version: "1.0.0"
purity: impure
signature: "GraphContainer(props: GraphContainerProps): JSX.Element"
description: "Interactive graph visualization with sigma.js, graphology, and ForceAtlas2 layout"
tags: [component, ui, graph, visualization, sigma, graphology, network]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: ["graphology", "graphology-layout-forceatlas2", "sigma"]
tested: false
tests: []
test_file_path: ""
file_path: "frontend/functions/ui/graph/index.tsx"
props:
- name: data
type: "GraphData"
required: true
description: "Graph data with nodes and edges arrays"
- name: layout
type: "'organic' | 'random'"
required: false
description: "Layout algorithm (default: organic/ForceAtlas2)"
- name: showLegend
type: "boolean"
required: false
description: "Show node type legend overlay"
- name: nodeTypes
type: "NodeType[]"
required: false
description: "Node type definitions for legend"
- name: onNodeClick
type: "(node: GraphNode) => void"
required: false
description: "Node click handler"
- name: onNodeDoubleClick
type: "(node: GraphNode) => void"
required: false
description: "Node double-click handler"
- name: theme
type: "GraphTheme"
required: false
description: "Visual theme overrides"
- name: height
type: "string | number"
required: false
description: "Container height (default: 100%)"
- name: className
type: "string"
required: false
description: "Additional CSS classes"
emits: []
has_state: true
framework: react
variant: []
---
## Ejemplo
```tsx
import { GraphContainer } from '@fn_library/graph'
import type { GraphData } from '@fn_library/graph'
const data: GraphData = {
nodes: [
{ id: '1', label: 'Node A', color: '#e74c3c', size: 10 },
{ id: '2', label: 'Node B', color: '#3498db', size: 8 },
],
edges: [
{ id: 'e1', source: '1', target: '2', label: 'connects', type: 'arrow' },
],
}
function MyGraph() {
return (
<GraphContainer
data={data}
layout="organic"
showLegend
nodeTypes={[
{ type: 'person', color: '#e74c3c', label: 'Person' },
{ type: 'org', color: '#3498db', label: 'Organization' },
]}
onNodeClick={(node) => console.log('clicked:', node.id)}
height="500px"
/>
)
}
```
## Notas
- Usa graphology como estructura de datos de grafo
- ForceAtlas2 para layout organico (iterations adaptativas segun numero de nodos)
- Sigma.js para renderizado WebGL de alto rendimiento
- Soporta grafos dirigidos multi-edge
- El componente limpia la instancia Sigma al desmontar
+237
View File
@@ -0,0 +1,237 @@
import * as React from "react"
import Graph from "graphology"
import forceAtlas2 from "graphology-layout-forceatlas2"
import { Sigma } from "sigma"
// ── Types ─────────────────────────────────────────────────────────────────
export interface GraphNode {
id: string
label: string
type?: string
color?: string
size?: number
x?: number
y?: number
[key: string]: unknown
}
export interface GraphEdge {
id: string
source: string
target: string
label?: string
color?: string
size?: number
type?: "arrow" | "line"
weight?: number
[key: string]: unknown
}
export interface GraphData {
nodes: GraphNode[]
edges: GraphEdge[]
}
export interface NodeType {
type: string
color: string
label: string
}
export interface GraphTheme {
backgroundColor?: string
nodeColor?: string
nodeSize?: number
edgeColor?: string
edgeSize?: number
labelColor?: string
selectionColor?: string
}
export interface GraphContainerProps {
data: GraphData
layout?: "organic" | "random"
showToolbar?: boolean
showLegend?: boolean
showMinimap?: boolean
nodeTypes?: NodeType[]
onNodeClick?: (node: GraphNode) => void
onNodeDoubleClick?: (node: GraphNode) => void
enableSelection?: boolean
selectionMode?: "single" | "multiple"
theme?: GraphTheme
height?: string | number
className?: string
}
const DEFAULT_THEME: Required<GraphTheme> = {
backgroundColor: "var(--background, #0a0a0f)",
nodeColor: "#95a5a6",
nodeSize: 8,
edgeColor: "rgba(255,255,255,0.19)",
edgeSize: 1,
labelColor: "#e0e0e0",
selectionColor: "#3b82f6",
}
// ── Component ─────────────────────────────────────────────────────────────
function GraphContainer({
data,
layout = "organic",
showLegend = false,
nodeTypes = [],
onNodeClick,
onNodeDoubleClick,
theme: themeProp,
height = "100%",
className,
}: GraphContainerProps) {
const containerRef = React.useRef<HTMLDivElement>(null)
const sigmaRef = React.useRef<Sigma | null>(null)
const graphRef = React.useRef<Graph | null>(null)
const theme = React.useMemo(
() => ({ ...DEFAULT_THEME, ...themeProp }),
[themeProp],
)
// Build + render
React.useEffect(() => {
const el = containerRef.current
if (!el) return
// Cleanup previous instance
if (sigmaRef.current) {
sigmaRef.current.kill()
sigmaRef.current = null
}
const g = new Graph({ multi: true, type: "directed" })
graphRef.current = g
// Add nodes
for (const n of data.nodes) {
g.addNode(n.id, {
label: n.label,
x: n.x ?? (Math.random() - 0.5) * 10,
y: n.y ?? (Math.random() - 0.5) * 10,
size: n.size ?? theme.nodeSize,
color: n.color ?? theme.nodeColor,
type: n.type,
})
}
// Add edges
for (const e of data.edges) {
try {
g.addEdgeWithKey(e.id, e.source, e.target, {
label: e.label,
size: e.size ?? theme.edgeSize,
color: e.color ?? theme.edgeColor,
type: e.type === "arrow" ? "arrow" : "line",
weight: e.weight ?? 1,
})
} catch {
// skip duplicate keys
}
}
// Layout
if (layout === "organic" && g.order > 0) {
forceAtlas2.assign(g, {
iterations: Math.min(500, Math.max(100, g.order * 5)),
settings: {
gravity: 1,
scalingRatio: 2,
slowDown: 5,
barnesHutOptimize: g.order > 300,
},
})
}
// Render
const renderer = new Sigma(g, el, {
renderEdgeLabels: false,
defaultEdgeColor: theme.edgeColor,
defaultNodeColor: theme.nodeColor,
labelColor: { color: theme.labelColor },
labelSize: 11,
})
sigmaRef.current = renderer
// Events
if (onNodeClick) {
renderer.on("clickNode", ({ node }) => {
const attrs = g.getNodeAttributes(node)
onNodeClick({ id: node, ...attrs } as unknown as GraphNode)
})
}
if (onNodeDoubleClick) {
renderer.on("doubleClickNode", ({ node }) => {
const attrs = g.getNodeAttributes(node)
onNodeDoubleClick({ id: node, ...attrs } as unknown as GraphNode)
})
}
return () => {
renderer.kill()
sigmaRef.current = null
graphRef.current = null
}
}, [data, layout, theme, onNodeClick, onNodeDoubleClick])
// Container background
const containerStyle: React.CSSProperties = {
height,
width: "100%",
position: "relative",
background: theme.backgroundColor,
borderRadius: "var(--radius, 0.5rem)",
overflow: "hidden",
}
return (
<div className={className} style={containerStyle}>
<div ref={containerRef} style={{ width: "100%", height: "100%" }} />
{showLegend && nodeTypes.length > 0 && (
<div
style={{
position: "absolute",
top: 12,
right: 12,
background: "rgba(0,0,0,0.7)",
backdropFilter: "blur(6px)",
borderRadius: 8,
padding: "10px 14px",
fontSize: 12,
display: "flex",
flexDirection: "column",
gap: 6,
}}
>
{nodeTypes.map((nt) => (
<div
key={nt.type}
style={{ display: "flex", alignItems: "center", gap: 8 }}
>
<span
style={{
width: 10,
height: 10,
borderRadius: "50%",
background: nt.color,
flexShrink: 0,
}}
/>
<span style={{ color: theme.labelColor }}>{nt.label}</span>
</div>
))}
</div>
)}
</div>
)
}
export { GraphContainer }
+4
View File
@@ -114,6 +114,10 @@ export type { TextareaProps } from './textarea'
export { Toast, ToastProvider, ToastViewport, toastVariants, useToast } from './toast'
export type { ToastEntry, ToastProps, ToastViewportProps } from './toast'
// Search
export { SearchBar } from './search_bar'
export type { SearchBarProps } from './search_bar'
// Hooks — Canvas
export { useAnimatedCanvas } from './use_animated_canvas'
+64
View File
@@ -0,0 +1,64 @@
---
name: search_bar
kind: component
lang: ts
domain: ui
version: "1.0.0"
purity: impure
signature: "SearchBar(props: SearchBarProps): JSX.Element"
description: "Search input with debounce, search icon, and clear button"
tags: [component, ui, search, input, debounce]
uses_functions: [cn_ts_core]
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: ["lucide-react"]
tested: false
tests: []
test_file_path: ""
file_path: "frontend/functions/ui/search_bar.tsx"
props:
- name: onSearch
type: "(query: string) => void"
required: true
description: "Called with the debounced search query"
- name: placeholder
type: "string"
required: false
description: "Placeholder text (default: Search...)"
- name: debounceMs
type: "number"
required: false
description: "Debounce delay in ms (default: 300)"
- name: className
type: "string"
required: false
description: "Additional CSS classes"
emits: []
has_state: true
framework: react
variant: []
---
## Ejemplo
```tsx
import { SearchBar } from '@fn_library'
function MyPage() {
return (
<SearchBar
onSearch={(query) => console.log('search:', query)}
placeholder="Search entities..."
debounceMs={300}
/>
)
}
```
## Notas
- Debounce usa ref para evitar re-renders innecesarios del callback
- El icono de clear solo aparece cuando hay texto
- Usa CSS variables del tema para colores (border, input, foreground, muted-foreground)
+65
View File
@@ -0,0 +1,65 @@
import * as React from "react"
import { cn } from "../core/cn"
import { Search, X } from "lucide-react"
interface SearchBarProps {
/** Called with the debounced search query */
onSearch: (query: string) => void
/** Placeholder text */
placeholder?: string
/** Debounce delay in ms (default 300) */
debounceMs?: number
/** Additional CSS classes for the outer wrapper */
className?: string
}
function SearchBar({
onSearch,
placeholder = "Search...",
debounceMs = 300,
className,
}: SearchBarProps) {
const [query, setQuery] = React.useState("")
const timerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)
const onSearchRef = React.useRef(onSearch)
onSearchRef.current = onSearch
React.useEffect(() => {
if (timerRef.current) clearTimeout(timerRef.current)
timerRef.current = setTimeout(() => {
onSearchRef.current(query)
}, debounceMs)
return () => {
if (timerRef.current) clearTimeout(timerRef.current)
}
}, [query, debounceMs])
return (
<div
className={cn(
"flex flex-1 items-center gap-2 rounded border border-border bg-input px-2 py-1",
className,
)}
>
<Search size={14} className="text-muted-foreground shrink-0" />
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder={placeholder}
className="flex-1 bg-transparent text-sm text-foreground outline-none placeholder:text-muted-foreground"
/>
{query && (
<button
onClick={() => setQuery("")}
className="p-0.5 text-muted-foreground hover:text-foreground"
aria-label="Clear search"
>
<X size={12} />
</button>
)}
</div>
)
}
export { SearchBar }
export type { SearchBarProps }
+71 -68
View File
@@ -1,88 +1,91 @@
"use client"
import * as React from "react"
import { Select as SelectPrimitive } from "@base-ui/react/select"
import { ChevronDown, Check } from "lucide-react"
import { cn } from "../core/cn"
import { ChevronDown } from "lucide-react"
function Select<T>({ ...props }: SelectPrimitive.Root.Props<T>) {
return <SelectPrimitive.Root data-slot="select" {...props} />
// ── Native select wrapper ─────────────────────────────────────────────────
interface SelectProps extends React.ComponentPropsWithoutRef<"select"> {
placeholder?: string
}
function SelectValue({ ...props }: SelectPrimitive.Value.Props) {
return <SelectPrimitive.Value data-slot="select-value" {...props} />
const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
({ className, children, placeholder, ...props }, ref) => {
return (
<div className="relative">
<select
ref={ref}
data-slot="select"
className={cn(
"flex h-8 w-full appearance-none items-center rounded-lg border border-input bg-transparent px-2.5 pr-8 py-1 text-sm transition-colors outline-none",
"focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50",
"disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
"aria-invalid:border-destructive aria-invalid:ring-destructive/20",
className,
)}
{...props}
>
{placeholder && (
<option value="" disabled>
{placeholder}
</option>
)}
{children}
</select>
<ChevronDown className="pointer-events-none absolute right-2 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
</div>
)
},
)
Select.displayName = "Select"
// ── Sub-components (thin wrappers for API compatibility) ──────────────────
function SelectItem({
className,
...props
}: React.ComponentPropsWithoutRef<"option">) {
return <option className={className} {...props} />
}
function SelectTrigger({ className, children, ...props }: SelectPrimitive.Trigger.Props) {
return (
<SelectPrimitive.Trigger
data-slot="select-trigger"
className={cn(
"flex h-8 w-full items-center justify-between gap-2 rounded-lg border border-input bg-transparent px-2.5 py-1 text-sm transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 [&>span]:line-clamp-1",
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon>
<ChevronDown className="size-4 shrink-0 text-muted-foreground" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
)
function SelectGroup({
className,
...props
}: React.ComponentPropsWithoutRef<"optgroup">) {
return <optgroup className={className} {...props} />
}
function SelectPortal({ ...props }: SelectPrimitive.Portal.Props) {
return <SelectPrimitive.Portal data-slot="select-portal" {...props} />
function SelectGroupLabel(_props: { children?: React.ReactNode }) {
// optgroup uses `label` attr, this is a no-op for compatibility
return null
}
function SelectContent({ className, children, ...props }: SelectPrimitive.Positioner.Props) {
return (
<SelectPortal>
<SelectPrimitive.Positioner
data-slot="select-content"
className={cn(
"relative z-50 max-h-[300px] min-w-[8rem] overflow-hidden rounded-lg border bg-popover text-popover-foreground shadow-md",
"data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95",
"data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
className
)}
sideOffset={4}
{...props}
>
<SelectPrimitive.Popup className="w-full p-1">{children}</SelectPrimitive.Popup>
</SelectPrimitive.Positioner>
</SelectPortal>
)
// Stubs for barrel export compatibility — these are no-ops with native select
function SelectContent({ children }: { children?: React.ReactNode; className?: string }) {
return <>{children}</>
}
function SelectGroup({ ...props }: SelectPrimitive.Group.Props) {
return <SelectPrimitive.Group data-slot="select-group" {...props} />
function SelectTrigger({ children }: { children?: React.ReactNode; className?: string }) {
return <>{children}</>
}
function SelectGroupLabel({ className, ...props }: SelectPrimitive.GroupLabel.Props) {
return <SelectPrimitive.GroupLabel data-slot="select-group-label" className={cn("px-2 py-1.5 text-xs font-medium text-muted-foreground", className)} {...props} />
function SelectValue(_props: { placeholder?: string }) {
return null
}
function SelectItem({ className, children, ...props }: SelectPrimitive.Item.Props) {
return (
<SelectPrimitive.Item
data-slot="select-item"
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-md 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 size-4 items-center justify-center">
<SelectPrimitive.ItemIndicator><Check className="size-4" /></SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
)
function SelectPortal({ children }: { children?: React.ReactNode }) {
return <>{children}</>
}
function SelectSeparator({ className, ...props }: React.ComponentProps<"div">) {
return <div data-slot="select-separator" className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
return <div className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
}
export { Select, SelectContent, SelectGroup, SelectGroupLabel, SelectItem, SelectPortal, SelectSeparator, SelectTrigger, SelectValue }
export {
Select,
SelectContent,
SelectGroup,
SelectGroupLabel,
SelectItem,
SelectPortal,
SelectSeparator,
SelectTrigger,
SelectValue,
}
+42 -34
View File
@@ -2,15 +2,7 @@
import * as React from "react"
import { cn } from "../core/cn"
import {
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
SelectGroup,
SelectGroupLabel,
} from "./select"
import { ChevronDown } from "lucide-react"
export interface SimpleSelectOption {
value: string
@@ -31,12 +23,14 @@ interface SimpleSelectProps {
options: SimpleSelectOptions
placeholder?: string
disabled?: boolean
size?: 'sm' | 'default'
size?: "sm" | "default"
className?: string
}
function isGrouped(options: SimpleSelectOptions): options is SimpleSelectGroup[] {
return options.length > 0 && 'group' in options[0]
function isGrouped(
options: SimpleSelectOptions,
): options is SimpleSelectGroup[] {
return options.length > 0 && "group" in options[0]
}
function SimpleSelect({
@@ -45,39 +39,53 @@ function SimpleSelect({
options,
placeholder = "Select...",
disabled = false,
size = 'default',
size = "default",
className,
}: SimpleSelectProps) {
return (
<Select value={value} onValueChange={onValueChange} disabled={disabled}>
<SelectTrigger
<div className={cn("relative", className)}>
<select
value={value}
onChange={(e) => onValueChange(e.target.value)}
disabled={disabled}
className={cn(
size === 'sm' && 'h-7 text-xs px-2',
className
"flex w-full appearance-none items-center rounded-lg border border-input bg-transparent px-2.5 pr-8 text-sm transition-colors outline-none",
"focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50",
"disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
size === "sm" ? "h-7 text-xs px-2" : "h-8 py-1",
)}
>
<SelectValue placeholder={placeholder} />
</SelectTrigger>
<SelectContent>
{placeholder && !value && (
<option value="" disabled>
{placeholder}
</option>
)}
{isGrouped(options)
? options.map(g => (
<SelectGroup key={g.group}>
<SelectGroupLabel>{g.group}</SelectGroupLabel>
{g.items.map(item => (
<SelectItem key={item.value} value={item.value} disabled={item.disabled}>
? options.map((g) => (
<optgroup key={g.group} label={g.group}>
{g.items.map((item) => (
<option
key={item.value}
value={item.value}
disabled={item.disabled}
>
{item.label}
</SelectItem>
</option>
))}
</SelectGroup>
</optgroup>
))
: (options as SimpleSelectOption[]).map(item => (
<SelectItem key={item.value} value={item.value} disabled={item.disabled}>
: (options as SimpleSelectOption[]).map((item) => (
<option
key={item.value}
value={item.value}
disabled={item.disabled}
>
{item.label}
</SelectItem>
))
}
</SelectContent>
</Select>
</option>
))}
</select>
<ChevronDown className="pointer-events-none absolute right-2 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
</div>
)
}
+5
View File
@@ -18,10 +18,15 @@
"@fontsource-variable/geist": "^5.2.8",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"graphology": "^0.26.0",
"graphology-layout-forceatlas2": "^0.10.1",
"graphology-types": "^0.24.8",
"lucide-react": "^1.7.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"recharts": "^3.8.1",
"shadcn": "^4.1.1",
"sigma": "^3.0.2",
"tailwind-merge": "^3.5.0",
"tw-animate-css": "^1.4.0"
},
+355
View File
@@ -20,6 +20,15 @@ importers:
clsx:
specifier: ^2.1.1
version: 2.1.1
graphology:
specifier: ^0.26.0
version: 0.26.0(graphology-types@0.24.8)
graphology-layout-forceatlas2:
specifier: ^0.10.1
version: 0.10.1(graphology-types@0.24.8)
graphology-types:
specifier: ^0.24.8
version: 0.24.8
lucide-react:
specifier: ^1.7.0
version: 1.7.0(react@19.2.4)
@@ -29,9 +38,15 @@ importers:
react-dom:
specifier: ^19.2.4
version: 19.2.4(react@19.2.4)
recharts:
specifier: ^3.8.1
version: 3.8.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@19.2.4)(react@19.2.4)(redux@5.0.1)
shadcn:
specifier: ^4.1.1
version: 4.1.1(typescript@6.0.2)
sigma:
specifier: ^3.0.2
version: 3.0.2(graphology-types@0.24.8)
tailwind-merge:
specifier: ^3.5.0
version: 3.5.0
@@ -526,6 +541,17 @@ packages:
'@oxc-project/types@0.122.0':
resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==}
'@reduxjs/toolkit@2.11.2':
resolution: {integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==}
peerDependencies:
react: ^16.9.0 || ^17.0.0 || ^18 || ^19
react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0
peerDependenciesMeta:
react:
optional: true
react-redux:
optional: true
'@rolldown/binding-android-arm64@1.0.0-rc.12':
resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -628,6 +654,12 @@ packages:
resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==}
engines: {node: '>=18'}
'@standard-schema/spec@1.1.0':
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
'@standard-schema/utils@0.3.0':
resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
'@tailwindcss/node@4.2.2':
resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==}
@@ -724,6 +756,33 @@ packages:
'@tybys/wasm-util@0.10.1':
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
'@types/d3-array@3.2.2':
resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
'@types/d3-color@3.1.3':
resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==}
'@types/d3-ease@3.0.2':
resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==}
'@types/d3-interpolate@3.0.4':
resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==}
'@types/d3-path@3.1.1':
resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==}
'@types/d3-scale@4.0.9':
resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==}
'@types/d3-shape@3.1.8':
resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==}
'@types/d3-time@3.0.4':
resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==}
'@types/d3-timer@3.0.2':
resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==}
'@types/react-dom@19.2.3':
resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
peerDependencies:
@@ -735,6 +794,9 @@ packages:
'@types/statuses@2.0.6':
resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==}
'@types/use-sync-external-store@0.0.6':
resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==}
'@types/validate-npm-package-name@4.0.2':
resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==}
@@ -931,6 +993,50 @@ packages:
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
d3-array@3.2.4:
resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
engines: {node: '>=12'}
d3-color@3.1.0:
resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
engines: {node: '>=12'}
d3-ease@3.0.1:
resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
engines: {node: '>=12'}
d3-format@3.1.2:
resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==}
engines: {node: '>=12'}
d3-interpolate@3.0.1:
resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
engines: {node: '>=12'}
d3-path@3.1.0:
resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==}
engines: {node: '>=12'}
d3-scale@4.0.2:
resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
engines: {node: '>=12'}
d3-shape@3.2.0:
resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==}
engines: {node: '>=12'}
d3-time-format@4.1.0:
resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
engines: {node: '>=12'}
d3-time@3.1.0:
resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
engines: {node: '>=12'}
d3-timer@3.0.1:
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
engines: {node: '>=12'}
data-uri-to-buffer@4.0.1:
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
engines: {node: '>= 12'}
@@ -944,6 +1050,9 @@ packages:
supports-color:
optional: true
decimal.js-light@2.5.1:
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
dedent@1.7.2:
resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==}
peerDependencies:
@@ -1031,6 +1140,9 @@ packages:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
es-toolkit@1.45.1:
resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==}
esbuild@0.27.4:
resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==}
engines: {node: '>=18'}
@@ -1052,6 +1164,13 @@ packages:
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
engines: {node: '>= 0.6'}
eventemitter3@5.0.4:
resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
events@3.3.0:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
eventsource-parser@3.0.6:
resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==}
engines: {node: '>=18.0.0'}
@@ -1189,6 +1308,24 @@ packages:
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
graphology-layout-forceatlas2@0.10.1:
resolution: {integrity: sha512-ogzBeF1FvWzjkikrIFwxhlZXvD2+wlY54lqhsrWprcdPjopM2J9HoMweUmIgwaTvY4bUYVimpSsOdvDv1gPRFQ==}
peerDependencies:
graphology-types: '>=0.19.0'
graphology-types@0.24.8:
resolution: {integrity: sha512-hDRKYXa8TsoZHjgEaysSRyPdT6uB78Ci8WnjgbStlQysz7xR52PInxNsmnB7IBOM1BhikxkNyCVEFgmPKnpx3Q==}
graphology-utils@2.5.2:
resolution: {integrity: sha512-ckHg8MXrXJkOARk56ZaSCM1g1Wihe2d6iTmz1enGOz4W/l831MBCKSayeFQfowgF8wd+PQ4rlch/56Vs/VZLDQ==}
peerDependencies:
graphology-types: '>=0.23.0'
graphology@0.26.0:
resolution: {integrity: sha512-8SSImzgUUYC89Z042s+0r/vMibY7GX/Emz4LDO5e7jYXhuoWfHISPFJYjpRLUSJGq6UQ6xlenvX1p/hJdfXuXg==}
peerDependencies:
graphology-types: '>=0.24.0'
graphql@16.13.2:
resolution: {integrity: sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==}
engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
@@ -1232,6 +1369,12 @@ packages:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
immer@10.2.0:
resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==}
immer@11.1.4:
resolution: {integrity: sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==}
import-fresh@3.3.1:
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
engines: {node: '>=6'}
@@ -1239,6 +1382,10 @@ packages:
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
internmap@2.0.3:
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
engines: {node: '>=12'}
ip-address@10.1.0:
resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==}
engines: {node: '>= 12'}
@@ -1683,6 +1830,21 @@ packages:
peerDependencies:
react: ^19.2.4
react-is@19.2.4:
resolution: {integrity: sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==}
react-redux@9.2.0:
resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==}
peerDependencies:
'@types/react': ^18.2.25 || ^19
react: ^18.0 || ^19
redux: ^5.0.0
peerDependenciesMeta:
'@types/react':
optional: true
redux:
optional: true
react@19.2.4:
resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
engines: {node: '>=0.10.0'}
@@ -1691,6 +1853,22 @@ packages:
resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==}
engines: {node: '>= 4'}
recharts@3.8.1:
resolution: {integrity: sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==}
engines: {node: '>=18'}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
redux-thunk@3.1.0:
resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==}
peerDependencies:
redux: ^5.0.0
redux@5.0.1:
resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==}
require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
@@ -1785,6 +1963,9 @@ packages:
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
engines: {node: '>= 0.4'}
sigma@3.0.2:
resolution: {integrity: sha512-/BUbeOwPGruiBOm0YQQ6ZMcLIZ6tf/W+Jcm7dxZyAX0tK3WP9/sq7/NAWBxPIxVahdGjCJoGwej0Gdrv0DxlQQ==}
signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
@@ -1957,6 +2138,9 @@ packages:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
victory-vendor@37.3.6:
resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==}
vite@8.0.3:
resolution: {integrity: sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -2517,6 +2701,18 @@ snapshots:
'@oxc-project/types@0.122.0': {}
'@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1))(react@19.2.4)':
dependencies:
'@standard-schema/spec': 1.1.0
'@standard-schema/utils': 0.3.0
immer: 11.1.4
redux: 5.0.1
redux-thunk: 3.1.0(redux@5.0.1)
reselect: 5.1.1
optionalDependencies:
react: 19.2.4
react-redux: 9.2.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1)
'@rolldown/binding-android-arm64@1.0.0-rc.12':
optional: true
@@ -2575,6 +2771,10 @@ snapshots:
'@sindresorhus/merge-streams@4.0.0': {}
'@standard-schema/spec@1.1.0': {}
'@standard-schema/utils@0.3.0': {}
'@tailwindcss/node@4.2.2':
dependencies:
'@jridgewell/remapping': 2.3.5
@@ -2654,6 +2854,30 @@ snapshots:
tslib: 2.8.1
optional: true
'@types/d3-array@3.2.2': {}
'@types/d3-color@3.1.3': {}
'@types/d3-ease@3.0.2': {}
'@types/d3-interpolate@3.0.4':
dependencies:
'@types/d3-color': 3.1.3
'@types/d3-path@3.1.1': {}
'@types/d3-scale@4.0.9':
dependencies:
'@types/d3-time': 3.0.4
'@types/d3-shape@3.1.8':
dependencies:
'@types/d3-path': 3.1.1
'@types/d3-time@3.0.4': {}
'@types/d3-timer@3.0.2': {}
'@types/react-dom@19.2.3(@types/react@19.2.14)':
dependencies:
'@types/react': 19.2.14
@@ -2664,6 +2888,8 @@ snapshots:
'@types/statuses@2.0.6': {}
'@types/use-sync-external-store@0.0.6': {}
'@types/validate-npm-package-name@4.0.2': {}
'@vitejs/plugin-react@6.0.1(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0))':
@@ -2827,12 +3053,52 @@ snapshots:
csstype@3.2.3: {}
d3-array@3.2.4:
dependencies:
internmap: 2.0.3
d3-color@3.1.0: {}
d3-ease@3.0.1: {}
d3-format@3.1.2: {}
d3-interpolate@3.0.1:
dependencies:
d3-color: 3.1.0
d3-path@3.1.0: {}
d3-scale@4.0.2:
dependencies:
d3-array: 3.2.4
d3-format: 3.1.2
d3-interpolate: 3.0.1
d3-time: 3.1.0
d3-time-format: 4.1.0
d3-shape@3.2.0:
dependencies:
d3-path: 3.1.0
d3-time-format@4.1.0:
dependencies:
d3-time: 3.1.0
d3-time@3.1.0:
dependencies:
d3-array: 3.2.4
d3-timer@3.0.1: {}
data-uri-to-buffer@4.0.1: {}
debug@4.4.3:
dependencies:
ms: 2.1.3
decimal.js-light@2.5.1: {}
dedent@1.7.2: {}
deepmerge@4.3.1: {}
@@ -2896,6 +3162,8 @@ snapshots:
dependencies:
es-errors: 1.3.0
es-toolkit@1.45.1: {}
esbuild@0.27.4:
optionalDependencies:
'@esbuild/aix-ppc64': 0.27.4
@@ -2933,6 +3201,10 @@ snapshots:
etag@1.8.1: {}
eventemitter3@5.0.4: {}
events@3.3.0: {}
eventsource-parser@3.0.6: {}
eventsource@3.0.7:
@@ -3114,6 +3386,22 @@ snapshots:
graceful-fs@4.2.11: {}
graphology-layout-forceatlas2@0.10.1(graphology-types@0.24.8):
dependencies:
graphology-types: 0.24.8
graphology-utils: 2.5.2(graphology-types@0.24.8)
graphology-types@0.24.8: {}
graphology-utils@2.5.2(graphology-types@0.24.8):
dependencies:
graphology-types: 0.24.8
graphology@0.26.0(graphology-types@0.24.8):
dependencies:
events: 3.3.0
graphology-types: 0.24.8
graphql@16.13.2: {}
has-symbols@1.1.0: {}
@@ -3151,6 +3439,10 @@ snapshots:
ignore@5.3.2: {}
immer@10.2.0: {}
immer@11.1.4: {}
import-fresh@3.3.1:
dependencies:
parent-module: 1.0.1
@@ -3158,6 +3450,8 @@ snapshots:
inherits@2.0.4: {}
internmap@2.0.3: {}
ip-address@10.1.0: {}
ipaddr.js@1.9.1: {}
@@ -3516,6 +3810,17 @@ snapshots:
react: 19.2.4
scheduler: 0.27.0
react-is@19.2.4: {}
react-redux@9.2.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1):
dependencies:
'@types/use-sync-external-store': 0.0.6
react: 19.2.4
use-sync-external-store: 1.6.0(react@19.2.4)
optionalDependencies:
'@types/react': 19.2.14
redux: 5.0.1
react@19.2.4: {}
recast@0.23.11:
@@ -3526,6 +3831,32 @@ snapshots:
tiny-invariant: 1.3.3
tslib: 2.8.1
recharts@3.8.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@19.2.4)(react@19.2.4)(redux@5.0.1):
dependencies:
'@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1))(react@19.2.4)
clsx: 2.1.1
decimal.js-light: 2.5.1
es-toolkit: 1.45.1
eventemitter3: 5.0.4
immer: 10.2.0
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
react-is: 19.2.4
react-redux: 9.2.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1)
reselect: 5.1.1
tiny-invariant: 1.3.3
use-sync-external-store: 1.6.0(react@19.2.4)
victory-vendor: 37.3.6
transitivePeerDependencies:
- '@types/react'
- redux
redux-thunk@3.1.0(redux@5.0.1):
dependencies:
redux: 5.0.1
redux@5.0.1: {}
require-directory@2.1.1: {}
require-from-string@2.0.2: {}
@@ -3695,6 +4026,13 @@ snapshots:
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
sigma@3.0.2(graphology-types@0.24.8):
dependencies:
events: 3.3.0
graphology-utils: 2.5.2(graphology-types@0.24.8)
transitivePeerDependencies:
- graphology-types
signal-exit@3.0.7: {}
signal-exit@4.1.0: {}
@@ -3834,6 +4172,23 @@ snapshots:
vary@1.1.2: {}
victory-vendor@37.3.6:
dependencies:
'@types/d3-array': 3.2.2
'@types/d3-ease': 3.0.2
'@types/d3-interpolate': 3.0.4
'@types/d3-scale': 4.0.9
'@types/d3-shape': 3.1.8
'@types/d3-time': 3.0.4
'@types/d3-timer': 3.0.2
d3-array: 3.2.4
d3-ease: 3.0.1
d3-interpolate: 3.0.1
d3-scale: 4.0.2
d3-shape: 3.2.0
d3-time: 3.1.0
d3-timer: 3.0.1
vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0):
dependencies:
lightningcss: 1.32.0