From 90d892f422d3c1d91385a32ae52e8ad234d67f4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 09:46:07 +0000 Subject: [PATCH 01/17] Initial plan From a0708be9392d857fc1603d3aa38ed88288771a01 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 09:52:46 +0000 Subject: [PATCH 02/17] Add Zustand stores for editor and viewer state management Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- packages/learningmap/package.json | 4 +- packages/learningmap/src/editorStore.ts | 323 ++++++++++++++++++++++++ packages/learningmap/src/viewerStore.ts | 214 ++++++++++++++++ pnpm-lock.yaml | 39 +++ 4 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 packages/learningmap/src/editorStore.ts create mode 100644 packages/learningmap/src/viewerStore.ts diff --git a/packages/learningmap/package.json b/packages/learningmap/package.json index 517d57d..85b3882 100644 --- a/packages/learningmap/package.json +++ b/packages/learningmap/package.json @@ -40,7 +40,9 @@ "lucide-react": "^0.545.0", "react": "^19.2.0", "react-dom": "^19.2.0", - "tslib": "^2.8.1" + "tslib": "^2.8.1", + "zundo": "^2.3.0", + "zustand": "^5.0.8" }, "devDependencies": { "@types/react": "^19.2.2", diff --git a/packages/learningmap/src/editorStore.ts b/packages/learningmap/src/editorStore.ts new file mode 100644 index 0000000..3f09aa4 --- /dev/null +++ b/packages/learningmap/src/editorStore.ts @@ -0,0 +1,323 @@ +import { create } from 'zustand'; +import { temporal } from 'zundo'; +import { Node, Edge, applyNodeChanges, applyEdgeChanges, addEdge, NodeChange, EdgeChange, Connection } from '@xyflow/react'; +import { NodeData, RoadmapData, Settings, ImageNodeData, TextNodeData } from './types'; + +export interface EditorState { + // Core data + nodes: Node[]; + edges: Edge[]; + settings: Settings; + + // UI state + saved: boolean; + previewMode: boolean; + debugMode: boolean; + showGrid: boolean; + helpOpen: boolean; + drawerOpen: boolean; + settingsDrawerOpen: boolean; + edgeDrawerOpen: boolean; + shareDialogOpen: boolean; + loadExternalDialogOpen: boolean; + + // Selected items + selectedNodeId: string | null; + selectedNodeIds: string[]; + selectedEdge: Edge | null; + + // Other state + nextNodeId: number; + clipboard: { nodes: Node[]; edges: Edge[] } | null; + lastMousePosition: { x: number; y: number } | null; + shareLink: string; + pendingExternalId: string | null; + + // Debug settings + showCompletionNeeds: boolean; + showCompletionOptional: boolean; + showUnlockAfter: boolean; + + // Actions + onNodesChange: (changes: NodeChange>[]) => void; + onEdgesChange: (changes: EdgeChange[]) => void; + onConnect: (connection: Connection) => void; + setNodes: (nodes: Node[]) => void; + setEdges: (edges: Edge[]) => void; + setSettings: (settings: Settings) => void; + updateNode: (nodeId: string, updates: Partial>) => void; + updateNodeData: (nodeId: string, dataUpdates: Partial) => void; + updateNodes: (updates: Node[]) => void; + updateEdge: (edgeId: string, updates: Partial) => void; + deleteNode: (nodeId: string) => void; + deleteEdge: (edgeId: string) => void; + addNode: (node: Node) => void; + + // UI state setters + setSaved: (saved: boolean) => void; + setPreviewMode: (previewMode: boolean) => void; + setDebugMode: (debugMode: boolean) => void; + setShowGrid: (showGrid: boolean) => void; + setHelpOpen: (helpOpen: boolean) => void; + setDrawerOpen: (drawerOpen: boolean) => void; + setSettingsDrawerOpen: (settingsDrawerOpen: boolean) => void; + setEdgeDrawerOpen: (edgeDrawerOpen: boolean) => void; + setShareDialogOpen: (shareDialogOpen: boolean) => void; + setLoadExternalDialogOpen: (loadExternalDialogOpen: boolean) => void; + setSelectedNodeId: (nodeId: string | null) => void; + setSelectedNodeIds: (nodeIds: string[]) => void; + setSelectedEdge: (edge: Edge | null) => void; + setNextNodeId: (nextNodeId: number) => void; + setClipboard: (clipboard: { nodes: Node[]; edges: Edge[] } | null) => void; + setLastMousePosition: (position: { x: number; y: number } | null) => void; + setShareLink: (shareLink: string) => void; + setPendingExternalId: (pendingExternalId: string | null) => void; + setShowCompletionNeeds: (showCompletionNeeds: boolean) => void; + setShowCompletionOptional: (showCompletionOptional: boolean) => void; + setShowUnlockAfter: (showUnlockAfter: boolean) => void; + + // Bulk operations + loadRoadmapData: (roadmapData: RoadmapData) => void; + getRoadmapData: () => RoadmapData; + closeAllDrawers: () => void; + reset: () => void; +} + +const initialState = { + nodes: [], + edges: [], + settings: { background: { color: "#ffffff" } }, + saved: true, + previewMode: false, + debugMode: false, + showGrid: false, + helpOpen: false, + drawerOpen: false, + settingsDrawerOpen: false, + edgeDrawerOpen: false, + shareDialogOpen: false, + loadExternalDialogOpen: false, + selectedNodeId: null, + selectedNodeIds: [], + selectedEdge: null, + nextNodeId: 1, + clipboard: null, + lastMousePosition: null, + shareLink: "", + pendingExternalId: null, + showCompletionNeeds: true, + showCompletionOptional: true, + showUnlockAfter: true, +}; + +export const useEditorStore = create()( + temporal( + (set, get) => ({ + ...initialState, + + // ReactFlow handlers + onNodesChange: (changes) => { + set({ + nodes: applyNodeChanges(changes, get().nodes), + saved: false, + }); + }, + + onEdgesChange: (changes) => { + set({ + edges: applyEdgeChanges(changes, get().edges), + saved: false, + }); + }, + + onConnect: (connection) => { + set({ + edges: addEdge(connection, get().edges), + saved: false, + }); + }, + + // Node operations + setNodes: (nodes) => { + set({ nodes, saved: false }); + }, + + setEdges: (edges) => { + set({ edges, saved: false }); + }, + + setSettings: (settings) => { + set({ settings, saved: false }); + }, + + updateNode: (nodeId, updates) => { + set({ + nodes: get().nodes.map((n) => + n.id === nodeId ? { ...n, ...updates } : n + ), + saved: false, + }); + }, + + updateNodeData: (nodeId, dataUpdates) => { + set({ + nodes: get().nodes.map((n) => + n.id === nodeId ? { ...n, data: { ...n.data, ...dataUpdates } } : n + ), + saved: false, + }); + }, + + updateNodes: (updates) => { + set({ + nodes: get().nodes.map((n) => { + const updated = updates.find((un) => un.id === n.id); + return updated ? updated : n; + }), + saved: false, + }); + }, + + updateEdge: (edgeId, updates) => { + set({ + edges: get().edges.map((e) => + e.id === edgeId ? { ...e, ...updates } : e + ), + saved: false, + }); + // Update selected edge if it's the one being updated + const selectedEdge = get().selectedEdge; + if (selectedEdge && selectedEdge.id === edgeId) { + set({ selectedEdge: { ...selectedEdge, ...updates } }); + } + }, + + deleteNode: (nodeId) => { + set({ + nodes: get().nodes.filter((n) => n.id !== nodeId), + edges: get().edges.filter((e) => e.source !== nodeId && e.target !== nodeId), + saved: false, + }); + }, + + deleteEdge: (edgeId) => { + set({ + edges: get().edges.filter((e) => e.id !== edgeId), + saved: false, + }); + }, + + addNode: (node) => { + set({ + nodes: [...get().nodes, node], + saved: false, + }); + }, + + // UI state setters + setSaved: (saved) => set({ saved }), + setPreviewMode: (previewMode) => set({ previewMode }), + setDebugMode: (debugMode) => set({ debugMode }), + setShowGrid: (showGrid) => set({ showGrid }), + setHelpOpen: (helpOpen) => set({ helpOpen }), + setDrawerOpen: (drawerOpen) => set({ drawerOpen }), + setSettingsDrawerOpen: (settingsDrawerOpen) => set({ settingsDrawerOpen }), + setEdgeDrawerOpen: (edgeDrawerOpen) => set({ edgeDrawerOpen }), + setShareDialogOpen: (shareDialogOpen) => set({ shareDialogOpen }), + setLoadExternalDialogOpen: (loadExternalDialogOpen) => set({ loadExternalDialogOpen }), + setSelectedNodeId: (selectedNodeId) => set({ selectedNodeId }), + setSelectedNodeIds: (selectedNodeIds) => set({ selectedNodeIds }), + setSelectedEdge: (selectedEdge) => set({ selectedEdge }), + setNextNodeId: (nextNodeId) => set({ nextNodeId }), + setClipboard: (clipboard) => set({ clipboard }), + setLastMousePosition: (lastMousePosition) => set({ lastMousePosition }), + setShareLink: (shareLink) => set({ shareLink }), + setPendingExternalId: (pendingExternalId) => set({ pendingExternalId }), + setShowCompletionNeeds: (showCompletionNeeds) => set({ showCompletionNeeds }), + setShowCompletionOptional: (showCompletionOptional) => set({ showCompletionOptional }), + setShowUnlockAfter: (showUnlockAfter) => set({ showUnlockAfter }), + + // Bulk operations + loadRoadmapData: (roadmapData) => { + const nodesArr = Array.isArray(roadmapData?.nodes) ? roadmapData.nodes : []; + const edgesArr = Array.isArray(roadmapData?.edges) ? roadmapData.edges : []; + + const rawNodes = nodesArr.map((n) => ({ + ...n, + draggable: true, + className: n.data.color ? n.data.color : n.className, + data: { ...n.data }, + })); + + // Calculate next node ID + let nextNodeId = 1; + if (nodesArr.length > 0) { + const maxId = Math.max( + ...nodesArr + .map((n) => parseInt(n.id.replace(/\D/g, ""), 10)) + .filter((id) => !isNaN(id)) + ); + nextNodeId = maxId + 1; + } + + set({ + nodes: rawNodes, + edges: edgesArr, + settings: roadmapData?.settings || { background: { color: "#ffffff" } }, + nextNodeId, + }); + }, + + getRoadmapData: () => { + const state = get(); + return { + nodes: state.nodes.map((n) => ({ + id: n.id, + type: n.type, + position: n.position, + width: n.width, + height: n.height, + zIndex: n.zIndex, + data: n.data, + })), + edges: state.edges + .filter((e) => !e.id.startsWith("debug-")) + .map((e) => ({ + id: e.id, + source: e.source, + target: e.target, + sourceHandle: e.sourceHandle, + targetHandle: e.targetHandle, + animated: e.animated, + type: e.type, + style: e.style, + })), + settings: state.settings, + version: 1, + }; + }, + + closeAllDrawers: () => { + set({ + drawerOpen: false, + selectedNodeId: null, + edgeDrawerOpen: false, + selectedEdge: null, + settingsDrawerOpen: false, + }); + }, + + reset: () => { + set(initialState); + }, + }), + { + // Zundo options + limit: 100, + equality: (a, b) => a === b, + } + ) +); + +// Temporal store selector for accessing undo/redo state +export const useTemporalStore = useEditorStore.temporal; diff --git a/packages/learningmap/src/viewerStore.ts b/packages/learningmap/src/viewerStore.ts new file mode 100644 index 0000000..1a41115 --- /dev/null +++ b/packages/learningmap/src/viewerStore.ts @@ -0,0 +1,214 @@ +import { create } from 'zustand'; +import { Node, Edge, applyNodeChanges, NodeChange } from '@xyflow/react'; +import { NodeData, RoadmapData, RoadmapState, Settings } from './types'; +import { persist, createJSONStorage } from 'zustand/middleware'; + +export interface ViewerState { + // Core data + nodes: Node[]; + edges: Edge[]; + settings: Settings; + + // UI state + selectedNode: Node | null; + drawerOpen: boolean; + + // Actions + onNodesChange: (changes: NodeChange>[]) => void; + setNodes: (nodes: Node[]) => void; + setEdges: (edges: Edge[]) => void; + setSettings: (settings: Settings) => void; + updateNodeState: (nodeId: string, state: string) => void; + setSelectedNode: (node: Node | null) => void; + setDrawerOpen: (drawerOpen: boolean) => void; + + // Bulk operations + loadRoadmapData: (roadmapData: RoadmapData, initialState?: RoadmapState) => void; + getRoadmapState: (viewport: { x: number; y: number; zoom: number }) => RoadmapState; + updateNodesStates: () => void; +} + +const getStateMap = (nodes: Node[]) => { + const stateMap: Record = {}; + nodes.forEach((n) => { + if (n.data?.state) { + stateMap[n.id] = n.data.state; + } + }); + return stateMap; +}; + +const isCompleteState = (state: string) => + state === 'completed' || state === 'mastered'; + +const isInteractableNode = (node: Node) => { + return node.type === 'task' || node.type === 'topic'; +}; + +const calculateNodesStates = (nodes: Node[]) => { + const updatedNodes = [...nodes]; + + // Run twice to ensure all dependencies are resolved + for (let i = 0; i < 2; i++) { + const stateMap = getStateMap(updatedNodes); + + for (const node of updatedNodes) { + node.data.state = node.data?.state || 'locked'; + + // Check unlock conditions + if (node.data?.unlock?.after) { + const unlocked = node.data.unlock.after.every((depId: string) => + isCompleteState(stateMap[depId]) + ); + if (unlocked) { + if (node.data.state === 'locked') { + node.data.state = 'unlocked'; + } + } else { + node.data.state = 'locked'; + } + } + + if (node.data?.unlock?.date) { + const unlockDate = new Date(node.data.unlock.date); + const now = new Date(); + if (now >= unlockDate) { + if (node.data.state === 'locked') { + node.data.state = 'unlocked'; + } + } else { + node.data.state = 'locked'; + } + } + + if (!node.data?.unlock?.after && !node.data?.unlock?.date) { + if (node.data.state === 'locked') { + node.data.state = 'unlocked'; + } + } + + // Handle topic completion + if (node.type !== 'topic') continue; + + if (node.data?.completion?.needs) { + const noNeeds = node.data.completion.needs.every((need: string) => + isCompleteState(stateMap[need]) + ); + if (node.data.state === 'unlocked' && noNeeds) { + node.data.state = 'completed'; + } + } else if (!node.data?.completion?.needs && node.data.state === 'unlocked') { + node.data.state = 'completed'; + } + + if (node.data?.completion?.optional) { + const noOptional = node.data.completion.optional.every((opt: string) => + isCompleteState(stateMap[opt]) + ); + if (node.data.state === 'completed' && noOptional) { + node.data.state = 'mastered'; + } + } else if (!node.data?.completion?.optional && node.data.state === 'completed') { + node.data.state = 'mastered'; + } + } + } + + return updatedNodes; +}; + +export const useViewerStore = create()((set, get) => ({ + // Initial state + nodes: [], + edges: [], + settings: {}, + selectedNode: null, + drawerOpen: false, + + // ReactFlow handlers + onNodesChange: (changes) => { + set({ + nodes: applyNodeChanges(changes, get().nodes), + }); + }, + + // Basic setters + setNodes: (nodes) => { + set({ nodes }); + }, + + setEdges: (edges) => { + set({ edges }); + }, + + setSettings: (settings) => { + set({ settings }); + }, + + updateNodeState: (nodeId, state) => { + const updatedNodes = get().nodes.map((n) => + n.id === nodeId ? { ...n, data: { ...n.data, state } } : n + ); + + // Recalculate all node states + const recalculatedNodes = calculateNodesStates(updatedNodes); + set({ nodes: recalculatedNodes }); + }, + + setSelectedNode: (selectedNode) => { + set({ selectedNode }); + }, + + setDrawerOpen: (drawerOpen) => { + set({ drawerOpen }); + }, + + // Bulk operations + loadRoadmapData: (roadmapData, initialState) => { + const nodesArr = Array.isArray(roadmapData?.nodes) ? roadmapData.nodes : []; + const edgesArr = Array.isArray(roadmapData?.edges) ? roadmapData.edges : []; + + let rawNodes = nodesArr.map((n) => ({ + ...n, + draggable: false, + connectable: false, + selectable: isInteractableNode(n), + focusable: isInteractableNode(n), + data: { + ...n.data, + state: initialState?.nodes?.[n.id]?.state || n.data?.state, + }, + })); + + // Calculate node states + rawNodes = calculateNodesStates(rawNodes); + + set({ + nodes: rawNodes, + edges: edgesArr, + settings: roadmapData?.settings || {}, + }); + }, + + getRoadmapState: (viewport) => { + const minimalState: RoadmapState = { + nodes: {}, + x: viewport.x, + y: viewport.y, + zoom: viewport.zoom, + }; + + get().nodes.forEach((n) => { + if (n.data.state && n.type === 'task') { + minimalState.nodes[n.id] = { state: n.data.state }; + } + }); + + return minimalState; + }, + + updateNodesStates: () => { + const updatedNodes = calculateNodesStates(get().nodes); + set({ nodes: updatedNodes }); + }, +})); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7a62e0d..fcef677 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -83,6 +83,12 @@ importers: tslib: specifier: ^2.8.1 version: 2.8.1 + zundo: + specifier: ^2.3.0 + version: 2.3.0(zustand@5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0))) + zustand: + specifier: ^5.0.8 + version: 5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) devDependencies: '@types/react': specifier: ^19.2.2 @@ -2270,6 +2276,11 @@ packages: zod@4.1.12: resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} + zundo@2.3.0: + resolution: {integrity: sha512-4GXYxXA17SIKYhVbWHdSEU04P697IMyVGXrC2TnzoyohEAWytFNOKqOp5gTGvaW93F/PM5Y0evbGtOPF0PWQwQ==} + peerDependencies: + zustand: ^4.3.0 || ^5.0.0 + zustand@4.5.7: resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} engines: {node: '>=12.7.0'} @@ -2285,6 +2296,24 @@ packages: react: optional: true + zustand@5.0.8: + resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + snapshots: '@babel/code-frame@7.27.1': @@ -4408,9 +4437,19 @@ snapshots: zod@4.1.12: {} + zundo@2.3.0(zustand@5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0))): + dependencies: + zustand: 5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) + zustand@4.5.7(@types/react@19.2.2)(react@19.2.0): dependencies: use-sync-external-store: 1.6.0(react@19.2.0) optionalDependencies: '@types/react': 19.2.2 react: 19.2.0 + + zustand@5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)): + optionalDependencies: + '@types/react': 19.2.2 + react: 19.2.0 + use-sync-external-store: 1.6.0(react@19.2.0) From 8aa65b403b81b0c6ab2a702892e6aeb66d0a445c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 09:55:51 +0000 Subject: [PATCH 03/17] Migrate LearningMap viewer to use Zustand store Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- packages/learningmap/src/LearningMap.tsx | 152 +++++------------------ 1 file changed, 31 insertions(+), 121 deletions(-) diff --git a/packages/learningmap/src/LearningMap.tsx b/packages/learningmap/src/LearningMap.tsx index 11a15ac..098d049 100644 --- a/packages/learningmap/src/LearningMap.tsx +++ b/packages/learningmap/src/LearningMap.tsx @@ -1,14 +1,15 @@ -import { Controls, Edge, Node, Panel, ReactFlow, ReactFlowProvider, useEdgesState, useNodesState, useReactFlow } from "@xyflow/react"; +import { Controls, Edge, Node, Panel, ReactFlow, ReactFlowProvider, useReactFlow } from "@xyflow/react"; import { ImageNode } from "./nodes/ImageNode"; import { TaskNode } from "./nodes/TaskNode"; import { TextNode } from "./nodes/TextNode"; import { TopicNode } from "./nodes/TopicNode"; import { NodeData, RoadmapData, RoadmapState, Settings } from "./types"; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect } from "react"; import { parseRoadmapData } from "./helper"; import { Drawer } from "./Drawer"; import { ProgressTracker } from "./ProgressTracker"; import { getTranslations } from "./translations"; +import { useViewerStore } from "./viewerStore"; const nodeTypes = { topic: TopicNode, @@ -17,73 +18,6 @@ const nodeTypes = { text: TextNode, }; -const getStateMap = (nodes: Node[]) => { - const stateMap: Record = {}; - nodes.forEach(n => { - if (n.data?.state) { - stateMap[n.id] = n.data.state; - } - }); - return stateMap; -} - -const isCompleteState = (state: string) => state === 'completed' || state === 'mastered'; - -const updateNodesStates = (nodes: Node[]) => { - for (let i = 0; i < 2; i++) { - const stateMap = getStateMap(nodes); - for (const node of nodes) { - node.data.state = node.data?.state || 'locked'; - // check unlock conditions - if (node.data?.unlock?.after) { - const unlocked = node.data.unlock.after.every((depId: string) => isCompleteState(stateMap[depId])); - if (unlocked) { - if (node.data.state === "locked") { - node.data.state = 'unlocked'; - } - } else { - node.data.state = 'locked'; - } - } - if (node.data?.unlock?.date) { - const unlockDate = new Date(node.data.unlock.date); - const now = new Date(); - if (now >= unlockDate) { - if (node.data.state === "locked") { - node.data.state = 'unlocked'; - } - } else { - node.data.state = 'locked'; - } - } - if (!node.data?.unlock?.after && !node.data?.unlock?.date) { - if (node.data.state === "locked") { - node.data.state = 'unlocked'; - } - } - if (node.type != "topic") continue; - if (node.data?.completion?.needs) { - const noNeeds = node.data.completion.needs.every((need: string) => isCompleteState(stateMap[need])); - if (node.data.state === "unlocked" && noNeeds) { - node.data.state = 'completed'; - } - } else if (!node.data?.completion?.needs && node.data.state === "unlocked") { - node.data.state = 'completed'; - } - if (node.data?.completion?.optional) { - const noOptional = node.data.completion.optional.every((opt: string) => isCompleteState(stateMap[opt])); - if (node.data.state === "completed" && noOptional) { - node.data.state = 'mastered'; - } - } else if (!node.data?.completion?.optional && node.data.state === "completed") { - node.data.state = 'mastered'; - } - } - } - - return nodes; -}; - const isInteractableNode = (node: Node) => { return node.type === "task" || node.type === "topic"; } @@ -120,11 +54,20 @@ export function LearningMap({ language = "en", initialState }: LearningMapProps) { - const [nodes, setNodes, onNodesChange] = useNodesState([]); - const [edges, setEdges, onEdgesChange] = useEdgesState([]); - const [selectedNode, setSelectedNode] = useState | null>(null); - const [drawerOpen, setDrawerOpen] = useState(false); - const [settings, setSettings] = useState(); + // Use Zustand store + const nodes = useViewerStore(state => state.nodes); + const edges = useViewerStore(state => state.edges); + const settings = useViewerStore(state => state.settings); + const selectedNode = useViewerStore(state => state.selectedNode); + const drawerOpen = useViewerStore(state => state.drawerOpen); + const onNodesChange = useViewerStore(state => state.onNodesChange); + const setSelectedNode = useViewerStore(state => state.setSelectedNode); + const setDrawerOpen = useViewerStore(state => state.setDrawerOpen); + const loadRoadmapData = useViewerStore(state => state.loadRoadmapData); + const getRoadmapState = useViewerStore(state => state.getRoadmapState); + const updateNodesStates = useViewerStore(state => state.updateNodesStates); + const updateNodeState = useViewerStore(state => state.updateNodeState); + const { fitView, getViewport, setViewport } = useReactFlow(); // Use language from settings if available, otherwise use prop @@ -136,37 +79,12 @@ export function LearningMap({ const parsedRoadmap = parseRoadmapData(roadmapData); useEffect(() => { - async function loadRoadmap() { - const nodesArr = Array.isArray(parsedRoadmap?.nodes) ? parsedRoadmap.nodes : []; - const edgesArr = Array.isArray(parsedRoadmap?.edges) ? parsedRoadmap.edges : []; - - setSettings(parsedRoadmap?.settings || {}); - - let rawNodes = nodesArr.map((n) => { - return { - ...n, - draggable: false, - connectable: false, - selectable: isInteractableNode(n), - focusable: isInteractableNode(n), - data: { - ...n.data, - state: initialState?.nodes?.[n.id]?.state, - } - } - }); - - rawNodes = updateNodesStates(rawNodes); - - setViewport({ - x: initialState?.x || 0, - y: initialState?.y || 0, - zoom: initialState?.zoom || 1, - }); - setEdges(edgesArr); - setNodes(rawNodes); - } - loadRoadmap(); + loadRoadmapData(parsedRoadmap, initialState); + setViewport({ + x: initialState?.x || 0, + y: initialState?.y || 0, + zoom: initialState?.zoom || 1, + }); }, [roadmapData, initialState]); const onNodeClick = useCallback((_: any, node: Node, focus: boolean = false) => { @@ -177,34 +95,27 @@ export function LearningMap({ if (focus) { fitView({ nodes: [node], duration: 150 }); } - }, [fitView]); + }, [fitView, setSelectedNode, setDrawerOpen]); const closeDrawer = useCallback(() => { setDrawerOpen(false); setSelectedNode(null); - }, []); + }, [setDrawerOpen, setSelectedNode]); const updateNode = useCallback( (updatedNode: Node) => { - setNodes((nds) => { - let newNodes = nds.map((n) => (n.id === updatedNode.id ? updatedNode : n)) - newNodes = updateNodesStates(newNodes); - return newNodes; + if (updatedNode.data.state) { + updateNodeState(updatedNode.id, updatedNode.data.state); } - ); setSelectedNode(updatedNode); }, - [setNodes] + [updateNodeState, setSelectedNode] ); useEffect(() => { const viewport = getViewport(); - const minimalState: RoadmapState = { nodes: {}, x: viewport.x, y: viewport.y, zoom: viewport.zoom }; - nodes.forEach((n) => { - if (n.data.state && n.type === "task") { - minimalState.nodes[n.id] = { state: n.data.state }; - } - }); + const minimalState = getRoadmapState(viewport); + if (onChange) { onChange(minimalState); } else { @@ -213,7 +124,7 @@ export function LearningMap({ root.dispatchEvent(new CustomEvent("change", { detail: minimalState })); } } - }, [nodes]); + }, [nodes, onChange, getViewport, getRoadmapState]); const defaultEdgeOptions = { animated: false, @@ -245,7 +156,6 @@ export function LearningMap({ }; })} edges={edges} - onEdgesChange={onEdgesChange} onNodeClick={onNodeClick} onNodesChange={onNodesChange} nodeTypes={nodeTypes} From c55e625a8f86b6f61acdd657c48290152b852013 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 10:05:57 +0000 Subject: [PATCH 04/17] Migrate LearningMapEditor to use Zustand store with undo/redo Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- .../learningmap/src/LearningMapEditor.tsx | 391 +++++++----------- packages/learningmap/src/editorStore.ts | 20 +- 2 files changed, 175 insertions(+), 236 deletions(-) diff --git a/packages/learningmap/src/LearningMapEditor.tsx b/packages/learningmap/src/LearningMapEditor.tsx index a740508..6e195d8 100644 --- a/packages/learningmap/src/LearningMapEditor.tsx +++ b/packages/learningmap/src/LearningMapEditor.tsx @@ -1,13 +1,10 @@ -import { useState, useCallback, useEffect } from "react"; +import { useCallback, useEffect } from "react"; import { ReactFlow, Controls, - useNodesState, - useEdgesState, ColorMode, useReactFlow, Node, - addEdge, Connection, Edge, Background, @@ -31,7 +28,7 @@ import { EditorToolbar } from "./EditorToolbar"; import { parseRoadmapData } from "./helper"; import { LearningMap } from "./LearningMap"; import { Info, Redo, Undo, RotateCw, ShieldAlert, X } from "lucide-react"; -import useUndoable from "./useUndoable"; +import { useEditorStore, useTemporalStore } from "./editorStore"; import { MultiNodePanel } from "./MultiNodePanel"; import { getTranslations } from "./translations"; import { WelcomeMessage } from "./WelcomeMessage"; @@ -71,18 +68,75 @@ export function LearningMapEditor({ const parsedRoadmap = parseRoadmapData(roadmapData || ""); const { screenToFlowPosition, zoomIn, zoomOut, setCenter, fitView } = useReactFlow(); - const [roadmapState, setRoadmapState, { undo, redo, canUndo, canRedo, reset, resetInitialState }] = useUndoable(parsedRoadmap); - - const [saved, setSaved] = useState(true); - const [didUndoRedo, setDidUndoRedo] = useState(false); - const [previewMode, setPreviewMode] = useState(false); - const [debugMode, setDebugMode] = useState(false); - const [nodes, setNodes, onNodesChange] = useNodesState(parsedRoadmap.nodes); - const [edges, setEdges, onEdgesChange] = useEdgesState(parsedRoadmap.edges); - const [settings, setSettings] = useState(parsedRoadmap.settings); - const [showGrid, setShowGrid] = useState(false); - const [clipboard, setClipboard] = useState<{ nodes: Node[]; edges: Edge[] } | null>(null); - const [lastMousePosition, setLastMousePosition] = useState<{ x: number; y: number } | null>(null); + + // Use Zustand store + const nodes = useEditorStore(state => state.nodes); + const edges = useEditorStore(state => state.edges); + const settings = useEditorStore(state => state.settings); + const saved = useEditorStore(state => state.saved); + const previewMode = useEditorStore(state => state.previewMode); + const debugMode = useEditorStore(state => state.debugMode); + const showGrid = useEditorStore(state => state.showGrid); + const helpOpen = useEditorStore(state => state.helpOpen); + const drawerOpen = useEditorStore(state => state.drawerOpen); + const settingsDrawerOpen = useEditorStore(state => state.settingsDrawerOpen); + const edgeDrawerOpen = useEditorStore(state => state.edgeDrawerOpen); + const shareDialogOpen = useEditorStore(state => state.shareDialogOpen); + const loadExternalDialogOpen = useEditorStore(state => state.loadExternalDialogOpen); + const selectedNodeId = useEditorStore(state => state.selectedNodeId); + const selectedNodeIds = useEditorStore(state => state.selectedNodeIds); + const selectedEdge = useEditorStore(state => state.selectedEdge); + const nextNodeId = useEditorStore(state => state.nextNodeId); + const clipboard = useEditorStore(state => state.clipboard); + const lastMousePosition = useEditorStore(state => state.lastMousePosition); + const shareLink = useEditorStore(state => state.shareLink); + const pendingExternalId = useEditorStore(state => state.pendingExternalId); + const showCompletionNeeds = useEditorStore(state => state.showCompletionNeeds); + const showCompletionOptional = useEditorStore(state => state.showCompletionOptional); + const showUnlockAfter = useEditorStore(state => state.showUnlockAfter); + + // Store actions + const onNodesChange = useEditorStore(state => state.onNodesChange); + const onEdgesChange = useEditorStore(state => state.onEdgesChange); + const onConnect = useEditorStore(state => state.onConnect); + const setSaved = useEditorStore(state => state.setSaved); + const setPreviewMode = useEditorStore(state => state.setPreviewMode); + const setDebugMode = useEditorStore(state => state.setDebugMode); + const setShowGrid = useEditorStore(state => state.setShowGrid); + const setHelpOpen = useEditorStore(state => state.setHelpOpen); + const setDrawerOpen = useEditorStore(state => state.setDrawerOpen); + const setSettingsDrawerOpen = useEditorStore(state => state.setSettingsDrawerOpen); + const setEdgeDrawerOpen = useEditorStore(state => state.setEdgeDrawerOpen); + const setShareDialogOpen = useEditorStore(state => state.setShareDialogOpen); + const setLoadExternalDialogOpen = useEditorStore(state => state.setLoadExternalDialogOpen); + const setSelectedNodeId = useEditorStore(state => state.setSelectedNodeId); + const setSelectedNodeIds = useEditorStore(state => state.setSelectedNodeIds); + const setSelectedEdge = useEditorStore(state => state.setSelectedEdge); + const setNextNodeId = useEditorStore(state => state.setNextNodeId); + const setClipboard = useEditorStore(state => state.setClipboard); + const setLastMousePosition = useEditorStore(state => state.setLastMousePosition); + const setShareLink = useEditorStore(state => state.setShareLink); + const setPendingExternalId = useEditorStore(state => state.setPendingExternalId); + const setShowCompletionNeeds = useEditorStore(state => state.setShowCompletionNeeds); + const setShowCompletionOptional = useEditorStore(state => state.setShowCompletionOptional); + const setShowUnlockAfter = useEditorStore(state => state.setShowUnlockAfter); + const updateNode = useEditorStore(state => state.updateNode); + const updateNodes = useEditorStore(state => state.updateNodes); + const updateEdge = useEditorStore(state => state.updateEdge); + const deleteNode = useEditorStore(state => state.deleteNode); + const deleteEdge = useEditorStore(state => state.deleteEdge); + const addNode = useEditorStore(state => state.addNode); + const loadRoadmapData = useEditorStore(state => state.loadRoadmapData); + const getRoadmapData = useEditorStore(state => state.getRoadmapData); + const closeAllDrawers = useEditorStore(state => state.closeAllDrawers); + const setNodes = useEditorStore(state => state.setNodes); + const setEdges = useEditorStore(state => state.setEdges); + const setSettings = useEditorStore(state => state.setSettings); + + // Temporal store for undo/redo + const { undo, redo, canUndo, canRedo } = useTemporalStore(); + + const colorMode: ColorMode = "light"; // Use language from settings if available, otherwise use prop const effectiveLanguage = settings?.language || language; @@ -113,67 +167,9 @@ export function LearningMapEditor({ { action: t.shortcuts.paste, shortcut: "Ctrl+V" }, ]; - const [helpOpen, setHelpOpen] = useState(false); - const [colorMode] = useState("light"); - const [selectedNodeId, setSelectedNodeId] = useState | null>(null); - const [selectedNodeIds, setSelectedNodeIds] = useState([]); - const [drawerOpen, setDrawerOpen] = useState(false); - const [settingsDrawerOpen, setSettingsDrawerOpen] = useState(false); - const [nextNodeId, setNextNodeId] = useState(1); - - // Debug settings state - const [showCompletionNeeds, setShowCompletionNeeds] = useState(true); - const [showCompletionOptional, setShowCompletionOptional] = useState(true); - const [showUnlockAfter, setShowUnlockAfter] = useState(true); - - // Share dialog state - const [shareDialogOpen, setShareDialogOpen] = useState(false); - const [shareLink, setShareLink] = useState(""); - const [loadExternalDialogOpen, setLoadExternalDialogOpen] = useState(false); - const [pendingExternalId, setPendingExternalId] = useState(null); - - // Edge drawer state - const [selectedEdge, setSelectedEdge] = useState(null); - const [edgeDrawerOpen, setEdgeDrawerOpen] = useState(false); - - useEffect(() => { - loadRoadmapStateIntoReactFlowState(parsedRoadmap); - resetInitialState(parsedRoadmap); - }, [roadmapData]) - - const loadRoadmapStateIntoReactFlowState = useCallback((roadmapState: RoadmapData) => { - const nodesArr = Array.isArray(roadmapState?.nodes) ? roadmapState.nodes : []; - const edgesArr = Array.isArray(roadmapState?.edges) ? roadmapState.edges : []; - - setSettings(roadmapState?.settings || { background: { color: "#ffffff" } }); - - const rawNodes = nodesArr.map((n) => ({ - ...n, - draggable: true, - className: n.data.color ? n.data.color : n.className, - data: { ...n.data }, - })); - - setEdges(edgesArr); - setNodes(rawNodes); - - // Calculate next node ID - if (nodesArr.length > 0) { - const maxId = Math.max( - ...nodesArr - .map((n) => parseInt(n.id.replace(/\D/g, ""), 10)) - .filter((id) => !isNaN(id)) - ); - setNextNodeId(maxId + 1); - } - }, [setNodes, setEdges, setSettings]); - useEffect(() => { - if (didUndoRedo) { - setDidUndoRedo(false); - loadRoadmapStateIntoReactFlowState(roadmapState); - } - }, [roadmapState, didUndoRedo, loadRoadmapStateIntoReactFlowState]); + loadRoadmapData(parsedRoadmap); + }, [roadmapData]); useEffect(() => { const newEdges: Edge[] = edges.filter((e) => !e.id.startsWith("debug-")); @@ -223,88 +219,60 @@ export function LearningMapEditor({ }); } setEdges(newEdges); - }, [nodes, setEdges, debugMode, showCompletionNeeds, showCompletionOptional, showUnlockAfter]); + }, [nodes, edges, setEdges, debugMode, showCompletionNeeds, showCompletionOptional, showUnlockAfter]); // Event handlers - const onNodeClick = useCallback((_: any, node: Node) => { + const handleNodeClick = useCallback((_: any, node: Node) => { setSelectedNodeId(node.id); setDrawerOpen(true); - }, []); + }, [setSelectedNodeId, setDrawerOpen]); - const onEdgeClick = useCallback((_: any, edge: Edge) => { + const handleEdgeClick = useCallback((_: any, edge: Edge) => { setSelectedEdge(edge); setEdgeDrawerOpen(true); - }, []); - - const onConnect = useCallback( - (connection: Connection) => { - setEdges((eds) => addEdge(connection, eds)); - setSaved(false); - }, - [setEdges, setSaved] - ); + }, [setSelectedEdge, setEdgeDrawerOpen]); const toggleDebugMode = useCallback(() => { - setDebugMode((mode) => !mode); - }, [setDebugMode]); + setDebugMode(!debugMode); + }, [debugMode, setDebugMode]); const closeDrawer = useCallback(() => { - setDrawerOpen(false); - setSelectedNodeId(null); - setEdgeDrawerOpen(false); - setSelectedEdge(null); - setSettingsDrawerOpen(false) - }, []); + closeAllDrawers(); + }, [closeAllDrawers]); - const updateNode = useCallback( + const handleUpdateNode = useCallback( (updatedNode: Node) => { - setNodes((nds) => - nds.map((n) => (n.id === updatedNode.id ? updatedNode : n)) - ); - setSaved(false); + updateNode(updatedNode.id, updatedNode); }, - [setNodes, setSaved] + [updateNode] ); - const updateNodes = useCallback( + const handleUpdateNodes = useCallback( (updatedNodes: Node[]) => { - setNodes((nds) => nds.map(n => { - const updated = updatedNodes.find(un => un.id === n.id); - return updated ? updated : n; - })); - setSaved(false); + updateNodes(updatedNodes); }, - [setNodes, setSaved] + [updateNodes] ); - const updateEdge = useCallback( + const handleUpdateEdge = useCallback( (updatedEdge: Edge) => { - setEdges((eds) => - eds.map((e) => (e.id === updatedEdge.id ? { ...e, ...updatedEdge } : e)) - ); - setSelectedEdge(updatedEdge); - setSaved(false); + updateEdge(updatedEdge.id, updatedEdge); }, - [setEdges, setSelectedEdge, setSaved] + [updateEdge] ); // Delete selected edge - const deleteEdge = useCallback(() => { + const handleDeleteEdge = useCallback(() => { if (!selectedEdge) return; - setEdges((eds) => eds.filter((e) => e.id !== selectedEdge.id)); - setSaved(false); - closeDrawer(); - }, [selectedEdge, setEdges, closeDrawer]); + deleteEdge(selectedEdge.id); + closeAllDrawers(); + }, [selectedEdge, deleteEdge, closeAllDrawers]); - const deleteNode = useCallback(() => { + const handleDeleteNode = useCallback(() => { if (!selectedNodeId) return; - setNodes((nds) => nds.filter((n) => n.id !== selectedNodeId)); - setEdges((eds) => - eds.filter((e) => e.source !== selectedNodeId && e.target !== selectedNodeId) - ); - setSaved(false); - closeDrawer(); - }, [selectedNodeId, setNodes, setEdges, closeDrawer, setSaved]); + deleteNode(selectedNodeId); + closeAllDrawers(); + }, [selectedNodeId, deleteNode, closeAllDrawers]); const addNewNode = useCallback( (type: "task" | "topic" | "image" | "text") => { @@ -324,8 +292,8 @@ export function LearningMapEditor({ description: "", }, }; - setNodes((nds) => [...nds, newNode]); - setNextNodeId((id) => id + 1); + addNode(newNode); + setNextNodeId(nextNodeId + 1); } else if (type === "topic") { const newNode: Node = { id: `node${nextNodeId}`, @@ -337,8 +305,8 @@ export function LearningMapEditor({ description: "", }, }; - setNodes((nds) => [...nds, newNode]); - setNextNodeId((id) => id + 1); + addNode(newNode); + setNextNodeId(nextNodeId + 1); } else if (type === "image") { const newNode: Node = { @@ -350,8 +318,8 @@ export function LearningMapEditor({ src: "", }, }; - setNodes((nds) => [...nds, newNode]); - setNextNodeId((id) => id + 1); + addNode(newNode); + setNextNodeId(nextNodeId + 1); } else if (type === "text") { const newNode: Node = { id: `background-node${nextNodeId}`, @@ -364,41 +332,15 @@ export function LearningMapEditor({ color: "#e5e7eb", }, }; - setNodes((nds) => [...nds, newNode]); - setNextNodeId((id) => id + 1); + addNode(newNode); + setNextNodeId(nextNodeId + 1); } - setSaved(false); }, - [nextNodeId, lastMousePosition, screenToFlowPosition, setNodes, setSaved, t] + [nextNodeId, lastMousePosition, screenToFlowPosition, addNode, setNextNodeId, t] ); const handleSave = useCallback(() => { - const roadmapData: RoadmapData = { - nodes: nodes.map((n) => ({ - id: n.id, - type: n.type, - position: n.position, - width: n.width, - height: n.height, - zIndex: n.zIndex, - data: n.data, - })), - edges: edges.filter((e) => !e.id.startsWith("debug-")) - .map((e) => ({ - id: e.id, - source: e.source, - target: e.target, - sourceHandle: e.sourceHandle, - targetHandle: e.targetHandle, - animated: e.animated, - type: e.type, - style: e.style, - })), - settings, - version: 1 - }; - - setRoadmapState(roadmapData); + const roadmapData = getRoadmapData(); setSaved(true); if (onChange) { @@ -410,7 +352,7 @@ export function LearningMapEditor({ root.dispatchEvent(new CustomEvent("change", { detail: roadmapData })); } } - }, [nodes, edges, settings]); + }, [nodes, edges, settings, onChange, getRoadmapData, setSaved]); // Auto-save when changes are made useEffect(() => { @@ -423,29 +365,30 @@ export function LearningMapEditor({ const togglePreviewMode = useCallback(() => { handleSave(); - setPreviewMode((mode) => { - const newMode = !mode; - if (newMode) { - setDebugMode(false); - closeDrawer(); - } - return newMode; - }); - }, [setPreviewMode, handleSave]); + const newMode = !previewMode; + setPreviewMode(newMode); + if (newMode) { + setDebugMode(false); + closeDrawer(); + } + }, [previewMode, setPreviewMode, setDebugMode, handleSave, closeDrawer]); const handleDownload = useCallback(() => { - const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(roadmapState, null, 2)); + const roadmapData = getRoadmapData(); + const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(roadmapData, null, 2)); const downloadAnchorNode = document.createElement('a'); downloadAnchorNode.setAttribute("href", dataStr); - downloadAnchorNode.setAttribute("download", `${roadmapState.settings.title?.trim() ?? getDefaultFilename()}.learningmap`); + downloadAnchorNode.setAttribute("download", `${roadmapData.settings.title?.trim() ?? getDefaultFilename()}.learningmap`); document.body.appendChild(downloadAnchorNode); // required for firefox downloadAnchorNode.click(); downloadAnchorNode.remove(); - }, [roadmapState]); + }, [getRoadmapData]); const handleShare = useCallback(() => { + const roadmapData = getRoadmapData(); + // Check if map is empty (no nodes) - if (!roadmapState.nodes || roadmapState.nodes.length === 0) { + if (!roadmapData.nodes || roadmapData.nodes.length === 0) { alert(t.emptyMapCannotBeShared); return; } @@ -457,7 +400,7 @@ export function LearningMapEditor({ headers: { "Content-Type": "application/json", }, - body: JSON.stringify(roadmapState), + body: JSON.stringify(roadmapData), }) .then((r) => r.json()) .then((json) => { @@ -468,7 +411,7 @@ export function LearningMapEditor({ .catch(() => { alert(t.uploadFailed); }); - }, [roadmapState, jsonStore, t]); + }, [getRoadmapData, jsonStore, t, setShareLink, setShareDialogOpen]); const loadFromJsonStore = useCallback((id: string) => { fetch(`${jsonStore}/api/v2/${id}`, { @@ -478,20 +421,19 @@ export function LearningMapEditor({ .then((r) => r.text()) .then((text) => { const json = JSON.parse(text); - setRoadmapState(json); - loadRoadmapStateIntoReactFlowState(json); + loadRoadmapData(json); setLoadExternalDialogOpen(false); setPendingExternalId(null); }) .catch(() => { alert(t.loadFailed); }); - }, [jsonStore, t, setRoadmapState]); + }, [jsonStore, t, loadRoadmapData, setLoadExternalDialogOpen, setPendingExternalId]); const handleLoadExternal = useCallback((id: string) => { setPendingExternalId(id); setLoadExternalDialogOpen(true); - }, []); + }, [setPendingExternalId, setLoadExternalDialogOpen]); // Check for external JSON in URL hash on mount useEffect(() => { @@ -530,8 +472,7 @@ export function LearningMapEditor({ const content = evt.target?.result; if (typeof content === 'string') { const json = JSON.parse(content); - setRoadmapState(json); - loadRoadmapStateIntoReactFlowState(json); + loadRoadmapData(json); } } catch (err) { alert(t.failedToLoadFile); @@ -540,49 +481,40 @@ export function LearningMapEditor({ reader.readAsText(file); }; input.click(); - }, [setRoadmapState, setDidUndoRedo, t]); + }, [loadRoadmapData, t]); // Toolbar handler wrappers for EditorToolbar props - const handleOpenSettingsDrawer = useCallback(() => setSettingsDrawerOpen(true), []); - const handleSetShowCompletionNeeds = useCallback((checked: boolean) => setShowCompletionNeeds(checked), []); - const handleSetShowCompletionOptional = useCallback((checked: boolean) => setShowCompletionOptional(checked), []); - const handleSetShowUnlockAfter = useCallback((checked: boolean) => setShowUnlockAfter(checked), []); + const handleOpenSettingsDrawer = useCallback(() => setSettingsDrawerOpen(true), [setSettingsDrawerOpen]); + const handleSetShowCompletionNeeds = useCallback((checked: boolean) => setShowCompletionNeeds(checked), [setShowCompletionNeeds]); + const handleSetShowCompletionOptional = useCallback((checked: boolean) => setShowCompletionOptional(checked), [setShowCompletionOptional]); + const handleSetShowUnlockAfter = useCallback((checked: boolean) => setShowUnlockAfter(checked), [setShowUnlockAfter]); const handleNodesChange: OnNodesChange = useCallback( (changes) => { - setSaved(false); onNodesChange(changes); }, - [onNodesChange, setSaved] + [onNodesChange] ); const handleEdgesChange: OnEdgesChange = useCallback( (changes) => { - setSaved(false); onEdgesChange(changes); }, - [onEdgesChange, setSaved] + [onEdgesChange] ); const handleUndo = useCallback(() => { if (canUndo) { undo(); - setDidUndoRedo(true); } }, [canUndo, undo]); const handleRedo = useCallback(() => { if (canRedo) { redo(); - setDidUndoRedo(true); } }, [canRedo, redo]); - const handleReset = useCallback(() => { - reset(); - setDidUndoRedo(true); - }, [reset]); - const handleCut = useCallback(() => { const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); if (selectedNodes.length > 0) { @@ -592,14 +524,10 @@ export function LearningMapEditor({ ); setClipboard({ nodes: selectedNodes, edges: relatedEdges }); // Delete the selected nodes - setNodes(nds => nds.filter(n => !selectedNodeIdSet.has(n.id))); - setEdges(eds => eds.filter(e => - !selectedNodeIdSet.has(e.source) && !selectedNodeIdSet.has(e.target) - )); + selectedNodeIds.forEach(id => deleteNode(id)); setSelectedNodeIds([]); - setSaved(false); } - }, [nodes, edges, selectedNodeIds, setNodes, setEdges, setSelectedNodeIds, setSaved]); + }, [nodes, edges, selectedNodeIds, deleteNode, setSelectedNodeIds, setClipboard]); const handleCopy = useCallback(() => { const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); @@ -610,7 +538,7 @@ export function LearningMapEditor({ ); setClipboard({ nodes: selectedNodes, edges: relatedEdges }); } - }, [nodes, edges, selectedNodeIds]); + }, [nodes, edges, selectedNodeIds, setClipboard]); const handlePaste = useCallback(() => { if (!clipboard) return; @@ -643,12 +571,11 @@ export function LearningMapEditor({ target: idMapping[edge.target] || edge.target, })); - setNodes(nds => [...nds, ...newNodes]); - setEdges(eds => [...eds, ...newEdges]); + newNodes.forEach(node => addNode(node)); + setEdges([...edges, ...newEdges]); setNextNodeId(newNextNodeId); setSelectedNodeIds(newNodes.map(n => n.id)); - setSaved(false); - }, [clipboard, nextNodeId, setNodes, setEdges, setNextNodeId, setSelectedNodeIds, setSaved]); + }, [clipboard, nextNodeId, edges, addNode, setEdges, setNextNodeId, setSelectedNodeIds]); const handleZoomIn = useCallback(() => { zoomIn(); @@ -673,23 +600,19 @@ export function LearningMapEditor({ }, [selectedNodeIds, fitView]); const handleToggleGrid = useCallback(() => { - setShowGrid(prev => !prev); - }, []); + setShowGrid(!showGrid); + }, [showGrid, setShowGrid]); const handleResetMap = useCallback(() => { if (confirm(t.resetMapWarning)) { setNodes([]); setEdges([]); setNextNodeId(1); - setSaved(false); } - }, [setNodes, setEdges, setNextNodeId, setSaved, t]); + }, [setNodes, setEdges, setNextNodeId, t]); const handleSelectAll = useCallback(() => { - setNodes(nds => nds.map(n => ({ - ...n, - selected: true, - }))) + setSelectedNodeIds(nodes.map(n => n.id)); }, [nodes, setSelectedNodeIds]); const handleSelectionChange: OnSelectionChangeFunc = useCallback( @@ -749,7 +672,7 @@ export function LearningMapEditor({ if ((e.ctrlKey || e.metaKey) && (e.key === '?' || (e.shiftKey && e.key === '/'))) { e.preventDefault(); - setHelpOpen(h => !h); + setHelpOpen(!helpOpen); } //preview toggle shortcut if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'p' && !e.shiftKey) { @@ -853,7 +776,7 @@ export function LearningMapEditor({ onReset={handleResetMap} language={effectiveLanguage} /> - {previewMode && } + {previewMode && } {!previewMode && <>
- + setHelpOpen(true)}> @@ -905,23 +828,23 @@ export function LearningMapEditor({ {!saved && { handleSave(); }}> } - {selectedNodeIds.length > 1 && selectedNodeIds.includes(n.id))} onUpdate={updateNodes} />} + {selectedNodeIds.length > 1 && selectedNodeIds.includes(n.id))} onUpdate={handleUpdateNodes} />}
n.id === selectedNodeId)} isOpen={drawerOpen} onClose={closeDrawer} - onUpdate={updateNode} - onDelete={deleteNode} + onUpdate={handleUpdateNode} + onDelete={handleDeleteNode} language={effectiveLanguage} /> ()( ) ); -// Temporal store selector for accessing undo/redo state -export const useTemporalStore = useEditorStore.temporal; +// Hook for accessing temporal store (undo/redo) +import { useStore } from 'zustand'; + +export const useTemporalStore = () => { + const undo = useEditorStore.temporal.getState().undo; + const redo = useEditorStore.temporal.getState().redo; + const pastStates = useStore(useEditorStore.temporal, (state) => state.pastStates); + const futureStates = useStore(useEditorStore.temporal, (state) => state.futureStates); + + return { + undo, + redo, + pastStates, + futureStates, + canUndo: pastStates.length > 0, + canRedo: futureStates.length > 0, + }; +}; From 5c7bc2d0503e72fa755adfb62935536ffb8a7704 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 10:07:23 +0000 Subject: [PATCH 05/17] Remove custom useUndoable implementation (replaced by zundo) Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- .../learningmap/src/useUndoable/errors.ts | 9 -- packages/learningmap/src/useUndoable/index.ts | 126 ------------------ .../learningmap/src/useUndoable/mutate.ts | 117 ---------------- .../learningmap/src/useUndoable/reducer.ts | 88 ------------ packages/learningmap/src/useUndoable/types.ts | 63 --------- 5 files changed, 403 deletions(-) delete mode 100644 packages/learningmap/src/useUndoable/errors.ts delete mode 100644 packages/learningmap/src/useUndoable/index.ts delete mode 100644 packages/learningmap/src/useUndoable/mutate.ts delete mode 100644 packages/learningmap/src/useUndoable/reducer.ts delete mode 100644 packages/learningmap/src/useUndoable/types.ts diff --git a/packages/learningmap/src/useUndoable/errors.ts b/packages/learningmap/src/useUndoable/errors.ts deleted file mode 100644 index 6cb0102..0000000 --- a/packages/learningmap/src/useUndoable/errors.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const payloadError = (func: string) => { - return new Error(`NoPayloadError: ${func} requires a payload.`); -}; - -export const invalidBehaviorError = (behavior: string) => { - return new Error( - `Mutation behavior must be one of: mergePastReversed, mergePast, keepFuture, or destroyFuture. Not: ${behavior}`, - ); -}; diff --git a/packages/learningmap/src/useUndoable/index.ts b/packages/learningmap/src/useUndoable/index.ts deleted file mode 100644 index 228a67b..0000000 --- a/packages/learningmap/src/useUndoable/index.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { useReducer, useCallback } from "react"; - -import { reducer } from "./reducer"; - -import type { - Action, - MutationBehavior, - Options, - State, - UseUndoable, -} from "./types"; - -const initialState = { - past: [], - present: null, - future: [], -}; - -const defaultOptions: Options = { - behavior: "mergePastReversed", - historyLimit: 100, - ignoreIdenticalMutations: true, - cloneState: false, -}; - -const compileMutateOptions = (options: Options) => ({ - ...defaultOptions, - ...options, -}); - -const useUndoable = ( - initialPresent: T, - options: Options = defaultOptions, -): UseUndoable => { - const [state, dispatch] = useReducer, [Action]>(reducer, { - ...initialState, - present: initialPresent, - }); - - const canUndo = state.past.length !== 0; - const canRedo = state.future.length !== 0; - - const undo = useCallback(() => { - if (canUndo) { - dispatch({ type: "undo" }); - } - }, [canUndo]); - - const redo = useCallback(() => { - if (canRedo) { - dispatch({ type: "redo" }); - } - }, [canRedo]); - - const reset = useCallback( - (payload = initialPresent) => dispatch({ type: "reset", payload }), - [], - ); - const resetInitialState = useCallback( - (payload: T) => dispatch({ type: "resetInitialState", payload }), - [], - ); - - const update = useCallback( - (payload: T, mutationBehavior: MutationBehavior, ignoreAction: boolean) => - dispatch({ - type: "update", - payload, - behavior: mutationBehavior, - ignoreAction, - ...compileMutateOptions(options), - }), - [], - ); - - // We can ignore the undefined type error here because - // we are setting a default value to options. - const setState = useCallback( - ( - payload: any, - - // @ts-ignore - mutationBehavior: MutationBehavior = options.behavior, - ignoreAction: boolean = false, - ) => { - return update(payload, mutationBehavior, ignoreAction); - }, - [state], - ); - - // In some rare cases, the fact that the above setState - // function changes on every render can be problematic. - // Since we can't really avoid this (setState uses - // state.present), we must export another function that - // doesn't depend on the present state (and thus doesn't - // need to change). - const static_setState = ( - payload: any, - - // @ts-ignore - mutationBehavior: MutationBehavior = options.behavior, - ignoreAction: boolean = false, - ) => { - update(payload, mutationBehavior, ignoreAction); - }; - - return [ - state.present, - setState, - { - past: state.past, - future: state.future, - - undo, - canUndo, - redo, - canRedo, - - reset, - resetInitialState, - static_setState, - }, - ]; -}; - -export default useUndoable; diff --git a/packages/learningmap/src/useUndoable/mutate.ts b/packages/learningmap/src/useUndoable/mutate.ts deleted file mode 100644 index b5b9b85..0000000 --- a/packages/learningmap/src/useUndoable/mutate.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { payloadError, invalidBehaviorError } from "./errors"; - -import type { Action, State } from "./types"; - -const ensureLimit = (limit: number | undefined, arr: any[]) => { - // Ensures that the `past` array doesn't exceed - // the specified `limit` amount. This is referred - // to as the `historyLimit` within the public API. - - // The conditional check in the `mutate` function - // might pass a potentially `undefined` value, - // therefore we check if it's valid here. - if (!limit) return arr; - - let n = [...arr]; - - if (n.length <= limit) return arr; - - const exceedsBy = n.length - limit; - - if (exceedsBy === 1) { - // This isn't faster than splice, but it works; - // therefore, we're leaving it. - // https://www.measurethat.net/Benchmarks/Show/3454/0/slice-vs-splice-vs-shift-who-is-the-fastest-to-keep-con - n.shift(); - } else { - // This shouldn't ever happen, I think. - n.splice(0, exceedsBy); - } - - return n; -}; - -const mutate = (state: State, action: Action): State => { - const { past, present, future } = state; - const { - payload, - behavior, - historyLimit, - ignoreIdenticalMutations, - cloneState, - ignoreAction, - } = action; - - if (!payload || payload === undefined) { - // A mutation call requires a payload. - // I guess we _could_ simply set the state - // to `undefined` with an empty payload, - // but this would probably be considered - // unexpected behavior. - // - // If you want to set the state to `undefined`, - // pass that explicitly. - throw payloadError("mutate"); - } - - if (ignoreAction) { - return { - past, - present: payload, - future, - }; - } - - let mPast = [...past]; - - if (historyLimit !== "infinium" && historyLimit !== "infinity") { - mPast = ensureLimit(historyLimit, past); - } - - const isEqual = JSON.stringify(payload) === JSON.stringify(present); - - if (ignoreIdenticalMutations && isEqual) { - return cloneState ? { ...state } : state; - } - - // We need to clone the array here because - // calling `future.reverse()` will mutate the - // existing array, causing the `mergePast` and - // `mergePastReversed` behaviors to work the same - // way. - const futureClone = [...future]; - - const behaviorMap = { - mergePastReversed: { - past: [...mPast, ...futureClone.reverse(), present], - present: payload, - future: [], - }, - mergePast: { - past: [...mPast, ...future, present], - present: payload, - future: [], - }, - destroyFuture: { - past: [...mPast, present], - present: payload, - future: [], - }, - keepFuture: { - past: [...mPast, present], - present: payload, - future, - }, - }; - - // Defaults should handle this case; mostly to make TS happy - if (typeof behavior === "undefined") { - return behaviorMap.mergePastReversed; - } - - if (!behaviorMap.hasOwnProperty(behavior)) - throw invalidBehaviorError(behavior); - return behaviorMap[behavior]; -}; - -export { mutate }; diff --git a/packages/learningmap/src/useUndoable/reducer.ts b/packages/learningmap/src/useUndoable/reducer.ts deleted file mode 100644 index 8bfeed0..0000000 --- a/packages/learningmap/src/useUndoable/reducer.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { mutate } from "./mutate"; -import { payloadError } from "./errors"; - -import type { Action, State } from "./types"; - -export const reducer = (state: State, action: Action): State => { - const { past, present, future } = state; - - const undo = (): State => { - if (past.length === 0) { - return state; - } - - const previous = past[past.length - 1]; - const newPast = past.slice(0, past.length - 1); - - return { - past: newPast, - present: previous, - future: [present, ...future], - }; - }; - - const redo = (): State => { - if (future.length === 0) { - return state; - } - - const next = future[0]; - const newFuture = future.slice(1); - - return { - past: [...past, present], - present: next, - future: newFuture, - }; - }; - - // Transform functional updater to raw value by applying it - const transform = (action: Action) => { - action.payload = - typeof action.payload === "function" - ? action.payload(present) - : action.payload; - - return action; - }; - - const update = (): State => mutate(state, transform(action)); - - const reset = (): State => { - const { payload } = action; - - return { - past: [], - present: payload || state.present, - future: [], - }; - }; - - const resetInitialState = (): State => { - const { payload } = action; - - if (!payload) { - throw payloadError("resetInitialState"); - } - - // Duplicate the past for mutation - let mPast = [...past]; - mPast[0] = payload; - - return { - past: [...mPast], - present, - future: [...future], - }; - }; - - const actions = { - undo, - redo, - update, - reset, - resetInitialState, - }; - - return actions[action.type](); -}; diff --git a/packages/learningmap/src/useUndoable/types.ts b/packages/learningmap/src/useUndoable/types.ts deleted file mode 100644 index 5fd95b0..0000000 --- a/packages/learningmap/src/useUndoable/types.ts +++ /dev/null @@ -1,63 +0,0 @@ -export type ActionType = - | "undo" - | "redo" - | "update" - | "reset" - | "resetInitialState"; - -export type HistoryLimit = number | "infinium" | "infinity"; - -export type MutationBehavior = - | "mergePastReversed" - | "mergePast" - | "destroyFuture" - | "keepFuture"; - -export interface Action { - type: ActionType; - payload?: T; - behavior?: MutationBehavior; - historyLimit?: HistoryLimit; - ignoreIdenticalMutations?: boolean; - cloneState?: boolean; - ignoreAction?: boolean; -} - -export interface State { - past: T[]; - present: T; - future: T[]; -} - -export interface Options { - behavior?: MutationBehavior; - historyLimit?: HistoryLimit; - ignoreIdenticalMutations?: boolean; - cloneState?: boolean; -} - -export type UseUndoable = [ - T, - ( - payload: T | ((oldValue: T) => T), - behavior?: MutationBehavior, - ignoreAction?: boolean, - ) => void, - { - past: T[]; - future: T[]; - - undo: () => void; - canUndo: boolean; - redo: () => void; - canRedo: boolean; - - reset: (initialState?: T) => void; - resetInitialState: (newInitialState: T) => void; - static_setState: ( - payload: T, - behavior?: MutationBehavior, - ignoreAction?: boolean, - ) => void; - }, -]; From 4b8e2dd60646ac97cc89ca9d6a50333a7e9e67e9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 10:09:37 +0000 Subject: [PATCH 06/17] Export Zustand stores and add documentation comments Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- packages/learningmap/src/editorStore.ts | 2 ++ packages/learningmap/src/index.ts | 2 ++ packages/learningmap/src/viewerStore.ts | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/learningmap/src/editorStore.ts b/packages/learningmap/src/editorStore.ts index 9a8b44a..14985e7 100644 --- a/packages/learningmap/src/editorStore.ts +++ b/packages/learningmap/src/editorStore.ts @@ -3,6 +3,8 @@ import { temporal } from 'zundo'; import { Node, Edge, applyNodeChanges, applyEdgeChanges, addEdge, NodeChange, EdgeChange, Connection } from '@xyflow/react'; import { NodeData, RoadmapData, Settings, ImageNodeData, TextNodeData } from './types'; +// Note: This is a global store for the editor. Typically only one editor instance is active at a time. +// If you need multiple independent editor instances, consider creating store instances per component or using context. export interface EditorState { // Core data nodes: Node[]; diff --git a/packages/learningmap/src/index.ts b/packages/learningmap/src/index.ts index 0de8987..6a0aa5e 100644 --- a/packages/learningmap/src/index.ts +++ b/packages/learningmap/src/index.ts @@ -7,3 +7,5 @@ export type { RoadmapData, RoadmapState } from "./types"; export type { LearningMapProps } from "./LearningMap"; export type { LearningMapEditorProps } from "./LearningMapEditor"; export { LearningMap, LearningMapEditor }; +export { useEditorStore, useTemporalStore } from "./editorStore"; +export { useViewerStore } from "./viewerStore"; diff --git a/packages/learningmap/src/viewerStore.ts b/packages/learningmap/src/viewerStore.ts index 1a41115..d42858d 100644 --- a/packages/learningmap/src/viewerStore.ts +++ b/packages/learningmap/src/viewerStore.ts @@ -1,8 +1,9 @@ import { create } from 'zustand'; import { Node, Edge, applyNodeChanges, NodeChange } from '@xyflow/react'; import { NodeData, RoadmapData, RoadmapState, Settings } from './types'; -import { persist, createJSONStorage } from 'zustand/middleware'; +// Note: This is a global store. If you need multiple independent LearningMap instances +// on the same page, consider creating store instances per component or using context. export interface ViewerState { // Core data nodes: Node[]; From f210a539e4595170e4df2580434a64e5c59efa4f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 10:58:47 +0000 Subject: [PATCH 07/17] Fix infinite loop in debug mode edges effect Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- packages/learningmap/src/LearningMapEditor.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/learningmap/src/LearningMapEditor.tsx b/packages/learningmap/src/LearningMapEditor.tsx index 6e195d8..a658cd4 100644 --- a/packages/learningmap/src/LearningMapEditor.tsx +++ b/packages/learningmap/src/LearningMapEditor.tsx @@ -169,10 +169,13 @@ export function LearningMapEditor({ useEffect(() => { loadRoadmapData(parsedRoadmap); - }, [roadmapData]); + }, [roadmapData, loadRoadmapData]); useEffect(() => { - const newEdges: Edge[] = edges.filter((e) => !e.id.startsWith("debug-")); + // Filter out existing debug edges, but use the store's edges directly to avoid dependency loop + const baseEdges = useEditorStore.getState().edges.filter((e) => !e.id.startsWith("debug-")); + const newEdges: Edge[] = [...baseEdges]; + if (debugMode) { nodes.forEach((node) => { if (showCompletionNeeds && node.type === "topic" && node.data?.completion?.needs) { @@ -219,7 +222,7 @@ export function LearningMapEditor({ }); } setEdges(newEdges); - }, [nodes, edges, setEdges, debugMode, showCompletionNeeds, showCompletionOptional, showUnlockAfter]); + }, [nodes, debugMode, showCompletionNeeds, showCompletionOptional, showUnlockAfter, setEdges]); // Event handlers const handleNodeClick = useCallback((_: any, node: Node) => { From 64657ef63256a498f4db78b413bdf3e888e1ebd9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 11:21:36 +0000 Subject: [PATCH 08/17] Optimize performance by moving store hooks into child components Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- packages/learningmap/src/EdgeDrawer.tsx | 9 +-- packages/learningmap/src/EditorDrawer.tsx | 15 ++-- packages/learningmap/src/EditorToolbar.tsx | 41 +++++------ .../learningmap/src/LearningMapEditor.tsx | 68 ++++++------------- .../learningmap/src/LoadExternalDialog.tsx | 6 +- packages/learningmap/src/MultiNodePanel.tsx | 10 ++- packages/learningmap/src/SettingsDrawer.tsx | 10 +-- packages/learningmap/src/ShareDialog.tsx | 9 ++- 8 files changed, 78 insertions(+), 90 deletions(-) diff --git a/packages/learningmap/src/EdgeDrawer.tsx b/packages/learningmap/src/EdgeDrawer.tsx index 00a5a75..968ce10 100644 --- a/packages/learningmap/src/EdgeDrawer.tsx +++ b/packages/learningmap/src/EdgeDrawer.tsx @@ -3,10 +3,9 @@ import { X, Trash2, Save } from "lucide-react"; import { Edge } from "@xyflow/react"; import { EditorDrawerEdgeContent } from "./EditorDrawerEdgeContent"; import { getTranslations } from "./translations"; +import { useEditorStore } from "./editorStore"; interface EdgeDrawerProps { - edge: Edge | null; - isOpen: boolean; onClose: () => void; onUpdate: (edge: Edge) => void; onDelete: () => void; @@ -14,8 +13,6 @@ interface EdgeDrawerProps { } export const EdgeDrawer: React.FC = ({ - edge: selectedEdge, - isOpen: edgeDrawerOpen, onClose: closeDrawer, onUpdate: updateEdge, onDelete: deleteEdge, @@ -23,6 +20,10 @@ export const EdgeDrawer: React.FC = ({ }) => { const t = getTranslations(language); + // Get edge and drawer state from store + const selectedEdge = useEditorStore(state => state.selectedEdge); + const edgeDrawerOpen = useEditorStore(state => state.edgeDrawerOpen); + if (!selectedEdge || !edgeDrawerOpen) return null; return (
diff --git a/packages/learningmap/src/EditorDrawer.tsx b/packages/learningmap/src/EditorDrawer.tsx index ada1062..2d190bb 100644 --- a/packages/learningmap/src/EditorDrawer.tsx +++ b/packages/learningmap/src/EditorDrawer.tsx @@ -1,15 +1,15 @@ import React, { useState, useEffect } from "react"; import { X, Trash2, Save } from "lucide-react"; -import { Node, useReactFlow } from "@xyflow/react"; +import { Node } from "@xyflow/react"; import { EditorDrawerTaskContent } from "./EditorDrawerTaskContent"; import { EditorDrawerTopicContent } from "./EditorDrawerTopicContent"; import { EditorDrawerImageContent } from "./EditorDrawerImageContent"; import { EditorDrawerTextContent } from "./EditorDrawerTextContent"; import { Completion, NodeData } from "./types"; import { getTranslations } from "./translations"; +import { useEditorStore } from "./editorStore"; interface EditorDrawerProps { - node: Node | null; isOpen: boolean; onClose: () => void; onUpdate: (node: Node) => void; @@ -18,7 +18,6 @@ interface EditorDrawerProps { } export const EditorDrawer: React.FC = ({ - node, isOpen, onClose, onUpdate, @@ -26,9 +25,13 @@ export const EditorDrawer: React.FC = ({ language = "en", }) => { const t = getTranslations(language); + + // Get node and all nodes from store + const selectedNodeId = useEditorStore(state => state.selectedNodeId); + const nodes = useEditorStore(state => state.nodes); + const node = nodes.find(n => n.id === selectedNodeId) || null; + const [localNode, setLocalNode] = useState | null>(node); - const { getNodes } = useReactFlow(); - const allNodes = getNodes(); useEffect(() => { setLocalNode(node); @@ -37,7 +40,7 @@ export const EditorDrawer: React.FC = ({ if (!isOpen || !node || !localNode) return null; // Filter out the current node from selectable options - const nodeOptions = allNodes.filter(n => n.id !== node.id && n.type === "task" || n.type === "topic"); + const nodeOptions = nodes.filter(n => n.id !== node.id && (n.type === "task" || n.type === "topic")); // Helper for dropdowns const renderNodeSelect = (value: string, onChange: (id: string) => void) => ( diff --git a/packages/learningmap/src/EditorToolbar.tsx b/packages/learningmap/src/EditorToolbar.tsx index 4268581..b8cfa39 100644 --- a/packages/learningmap/src/EditorToolbar.tsx +++ b/packages/learningmap/src/EditorToolbar.tsx @@ -4,18 +4,9 @@ import "@szhsin/react-menu/dist/index.css"; import '@szhsin/react-menu/dist/transitions/zoom.css'; import { Plus, Bug, Settings, Eye, Menu as MenuI, FolderOpen, Download, ImageDown, ExternalLink, Share2, RotateCcw } from "lucide-react"; import { getTranslations } from "./translations"; +import { useEditorStore } from "./editorStore"; interface EditorToolbarProps { - debugMode: boolean; - previewMode: boolean; - showCompletionNeeds: boolean; - showCompletionOptional: boolean; - showUnlockAfter: boolean; - onToggleDebugMode: () => void; - onTogglePreviewMode: () => void; - onSetShowCompletionNeeds: (checked: boolean) => void; - onSetShowCompletionOptional: (checked: boolean) => void; - onSetShowUnlockAfter: (checked: boolean) => void; onAddNewNode: (type: "task" | "topic" | "image" | "text") => void; onOpenSettingsDrawer: () => void; onDownlad: () => void; @@ -26,16 +17,6 @@ interface EditorToolbarProps { } export const EditorToolbar: React.FC = ({ - debugMode, - previewMode, - showCompletionNeeds, - showCompletionOptional, - showUnlockAfter, - onTogglePreviewMode, - onToggleDebugMode, - onSetShowCompletionNeeds, - onSetShowCompletionOptional, - onSetShowUnlockAfter, onAddNewNode, onOpenSettingsDrawer, onDownlad, @@ -45,6 +26,26 @@ export const EditorToolbar: React.FC = ({ language = "en", }) => { const t = getTranslations(language); + + // Get state directly from store + const debugMode = useEditorStore(state => state.debugMode); + const previewMode = useEditorStore(state => state.previewMode); + const showCompletionNeeds = useEditorStore(state => state.showCompletionNeeds); + const showCompletionOptional = useEditorStore(state => state.showCompletionOptional); + const showUnlockAfter = useEditorStore(state => state.showUnlockAfter); + + // Get actions directly from store + const setDebugMode = useEditorStore(state => state.setDebugMode); + const setPreviewMode = useEditorStore(state => state.setPreviewMode); + const setShowCompletionNeeds = useEditorStore(state => state.setShowCompletionNeeds); + const setShowCompletionOptional = useEditorStore(state => state.setShowCompletionOptional); + const setShowUnlockAfter = useEditorStore(state => state.setShowUnlockAfter); + + const onToggleDebugMode = () => setDebugMode(!debugMode); + const onTogglePreviewMode = () => setPreviewMode(!previewMode); + const onSetShowCompletionNeeds = (checked: boolean) => setShowCompletionNeeds(checked); + const onSetShowCompletionOptional = (checked: boolean) => setShowCompletionOptional(checked); + const onSetShowUnlockAfter = (checked: boolean) => setShowUnlockAfter(checked); return (
diff --git a/packages/learningmap/src/LearningMapEditor.tsx b/packages/learningmap/src/LearningMapEditor.tsx index a658cd4..773b8d9 100644 --- a/packages/learningmap/src/LearningMapEditor.tsx +++ b/packages/learningmap/src/LearningMapEditor.tsx @@ -69,7 +69,7 @@ export function LearningMapEditor({ const parsedRoadmap = parseRoadmapData(roadmapData || ""); const { screenToFlowPosition, zoomIn, zoomOut, setCenter, fitView } = useReactFlow(); - // Use Zustand store + // Only get minimal state needed in this component const nodes = useEditorStore(state => state.nodes); const edges = useEditorStore(state => state.edges); const settings = useEditorStore(state => state.settings); @@ -78,48 +78,39 @@ export function LearningMapEditor({ const debugMode = useEditorStore(state => state.debugMode); const showGrid = useEditorStore(state => state.showGrid); const helpOpen = useEditorStore(state => state.helpOpen); - const drawerOpen = useEditorStore(state => state.drawerOpen); - const settingsDrawerOpen = useEditorStore(state => state.settingsDrawerOpen); - const edgeDrawerOpen = useEditorStore(state => state.edgeDrawerOpen); - const shareDialogOpen = useEditorStore(state => state.shareDialogOpen); - const loadExternalDialogOpen = useEditorStore(state => state.loadExternalDialogOpen); const selectedNodeId = useEditorStore(state => state.selectedNodeId); const selectedNodeIds = useEditorStore(state => state.selectedNodeIds); const selectedEdge = useEditorStore(state => state.selectedEdge); - const nextNodeId = useEditorStore(state => state.nextNodeId); - const clipboard = useEditorStore(state => state.clipboard); - const lastMousePosition = useEditorStore(state => state.lastMousePosition); - const shareLink = useEditorStore(state => state.shareLink); - const pendingExternalId = useEditorStore(state => state.pendingExternalId); const showCompletionNeeds = useEditorStore(state => state.showCompletionNeeds); const showCompletionOptional = useEditorStore(state => state.showCompletionOptional); const showUnlockAfter = useEditorStore(state => state.showUnlockAfter); + const lastMousePosition = useEditorStore(state => state.lastMousePosition); + const nextNodeId = useEditorStore(state => state.nextNodeId); + const clipboard = useEditorStore(state => state.clipboard); + const pendingExternalId = useEditorStore(state => state.pendingExternalId); // Store actions const onNodesChange = useEditorStore(state => state.onNodesChange); const onEdgesChange = useEditorStore(state => state.onEdgesChange); const onConnect = useEditorStore(state => state.onConnect); const setSaved = useEditorStore(state => state.setSaved); - const setPreviewMode = useEditorStore(state => state.setPreviewMode); - const setDebugMode = useEditorStore(state => state.setDebugMode); - const setShowGrid = useEditorStore(state => state.setShowGrid); const setHelpOpen = useEditorStore(state => state.setHelpOpen); + const setShowGrid = useEditorStore(state => state.setShowGrid); + const setSelectedNodeId = useEditorStore(state => state.setSelectedNodeId); + const setSelectedNodeIds = useEditorStore(state => state.setSelectedNodeIds); const setDrawerOpen = useEditorStore(state => state.setDrawerOpen); const setSettingsDrawerOpen = useEditorStore(state => state.setSettingsDrawerOpen); const setEdgeDrawerOpen = useEditorStore(state => state.setEdgeDrawerOpen); - const setShareDialogOpen = useEditorStore(state => state.setShareDialogOpen); - const setLoadExternalDialogOpen = useEditorStore(state => state.setLoadExternalDialogOpen); - const setSelectedNodeId = useEditorStore(state => state.setSelectedNodeId); - const setSelectedNodeIds = useEditorStore(state => state.setSelectedNodeIds); const setSelectedEdge = useEditorStore(state => state.setSelectedEdge); const setNextNodeId = useEditorStore(state => state.setNextNodeId); const setClipboard = useEditorStore(state => state.setClipboard); const setLastMousePosition = useEditorStore(state => state.setLastMousePosition); - const setShareLink = useEditorStore(state => state.setShareLink); + const setShareDialogOpen = useEditorStore(state => state.setShareDialogOpen); + const setLoadExternalDialogOpen = useEditorStore(state => state.setLoadExternalDialogOpen); const setPendingExternalId = useEditorStore(state => state.setPendingExternalId); - const setShowCompletionNeeds = useEditorStore(state => state.setShowCompletionNeeds); - const setShowCompletionOptional = useEditorStore(state => state.setShowCompletionOptional); - const setShowUnlockAfter = useEditorStore(state => state.setShowUnlockAfter); + const setShareLink = useEditorStore(state => state.setShareLink); + const setDebugMode = useEditorStore(state => state.setDebugMode); + const setPreviewMode = useEditorStore(state => state.setPreviewMode); const updateNode = useEditorStore(state => state.updateNode); const updateNodes = useEditorStore(state => state.updateNodes); const updateEdge = useEditorStore(state => state.updateEdge); @@ -235,10 +226,6 @@ export function LearningMapEditor({ setEdgeDrawerOpen(true); }, [setSelectedEdge, setEdgeDrawerOpen]); - const toggleDebugMode = useCallback(() => { - setDebugMode(!debugMode); - }, [debugMode, setDebugMode]); - const closeDrawer = useCallback(() => { closeAllDrawers(); }, [closeAllDrawers]); @@ -376,6 +363,10 @@ export function LearningMapEditor({ } }, [previewMode, setPreviewMode, setDebugMode, handleSave, closeDrawer]); + const toggleDebugMode = useCallback(() => { + setDebugMode(!debugMode); + }, [debugMode, setDebugMode]); + const handleDownload = useCallback(() => { const roadmapData = getRoadmapData(); const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(roadmapData, null, 2)); @@ -488,9 +479,6 @@ export function LearningMapEditor({ // Toolbar handler wrappers for EditorToolbar props const handleOpenSettingsDrawer = useCallback(() => setSettingsDrawerOpen(true), [setSettingsDrawerOpen]); - const handleSetShowCompletionNeeds = useCallback((checked: boolean) => setShowCompletionNeeds(checked), [setShowCompletionNeeds]); - const handleSetShowCompletionOptional = useCallback((checked: boolean) => setShowCompletionOptional(checked), [setShowCompletionOptional]); - const handleSetShowUnlockAfter = useCallback((checked: boolean) => setShowUnlockAfter(checked), [setShowUnlockAfter]); const handleNodesChange: OnNodesChange = useCallback( (changes) => { @@ -761,16 +749,6 @@ export function LearningMapEditor({ return ( <> { handleSave(); }}> } - {selectedNodeIds.length > 1 && selectedNodeIds.includes(n.id))} onUpdate={handleUpdateNodes} />} + {selectedNodeIds.length > 1 && }
n.id === selectedNodeId)} - isOpen={drawerOpen} + isOpen={true} onClose={closeDrawer} onUpdate={handleUpdateNode} onDelete={handleDeleteNode} language={effectiveLanguage} /> @@ -891,13 +864,10 @@ export function LearningMapEditor({
setShareDialogOpen(false)} - shareLink={shareLink} language={effectiveLanguage} /> { setLoadExternalDialogOpen(false); setPendingExternalId(null); diff --git a/packages/learningmap/src/LoadExternalDialog.tsx b/packages/learningmap/src/LoadExternalDialog.tsx index 3a3c275..b754184 100644 --- a/packages/learningmap/src/LoadExternalDialog.tsx +++ b/packages/learningmap/src/LoadExternalDialog.tsx @@ -1,9 +1,9 @@ import React from "react"; import { X, Download, AlertTriangle } from "lucide-react"; import { getTranslations } from "./translations"; +import { useEditorStore } from "./editorStore"; interface LoadExternalDialogProps { - open: boolean; onClose: () => void; onDownloadCurrent: () => void; onReplace: () => void; @@ -11,13 +11,15 @@ interface LoadExternalDialogProps { } export function LoadExternalDialog({ - open, onClose, onDownloadCurrent, onReplace, language = "en", }: LoadExternalDialogProps) { const t = getTranslations(language); + + // Get state from store + const open = useEditorStore(state => state.loadExternalDialogOpen); if (!open) return null; diff --git a/packages/learningmap/src/MultiNodePanel.tsx b/packages/learningmap/src/MultiNodePanel.tsx index 4843c23..86d6dae 100644 --- a/packages/learningmap/src/MultiNodePanel.tsx +++ b/packages/learningmap/src/MultiNodePanel.tsx @@ -2,13 +2,19 @@ import { Node, Panel } from "@xyflow/react"; import { NodeData } from "./types"; import { FC } from "react"; import { AlignCenterVertical, AlignCenterHorizontal, AlignEndHorizontal, AlignEndVertical, AlignStartVertical, AlignStartHorizontal, RulerDimensionLine, AlignVerticalDistributeCenter, AlignHorizontalDistributeCenter } from "lucide-react"; +import { useEditorStore } from "./editorStore"; interface Props { - nodes: Node[]; onUpdate: (nodes: Node[]) => void; } -export const MultiNodePanel: FC = ({ nodes, onUpdate }) => { +export const MultiNodePanel: FC = ({ onUpdate }) => { + // Get selected nodes from store + const selectedNodeIds = useEditorStore(state => state.selectedNodeIds); + const allNodes = useEditorStore(state => state.nodes); + const nodes = allNodes.filter(n => selectedNodeIds.includes(n.id)); + + if (nodes.length < 2) return null; const alignLeftVertical = () => { if (nodes.length < 2) return; diff --git a/packages/learningmap/src/SettingsDrawer.tsx b/packages/learningmap/src/SettingsDrawer.tsx index b0ea60f..15a5cf1 100644 --- a/packages/learningmap/src/SettingsDrawer.tsx +++ b/packages/learningmap/src/SettingsDrawer.tsx @@ -4,23 +4,25 @@ import { Settings } from "./types"; import { ColorSelector } from "./ColorSelector"; import { getTranslations } from "./translations"; import { useReactFlow } from "@xyflow/react"; +import { useEditorStore } from "./editorStore"; interface SettingsDrawerProps { - isOpen: boolean; onClose: () => void; - settings: Settings; onUpdate: (s: Settings) => void; language?: string; } export const SettingsDrawer: React.FC = ({ - isOpen, onClose, - settings, onUpdate, language = "en", }) => { const t = getTranslations(language); + + // Get state from store + const isOpen = useEditorStore(state => state.settingsDrawerOpen); + const settings = useEditorStore(state => state.settings); + const [localSettings, setLocalSettings] = useState(settings); const { getViewport } = useReactFlow(); diff --git a/packages/learningmap/src/ShareDialog.tsx b/packages/learningmap/src/ShareDialog.tsx index eb03bc5..4062ec6 100644 --- a/packages/learningmap/src/ShareDialog.tsx +++ b/packages/learningmap/src/ShareDialog.tsx @@ -1,17 +1,20 @@ import React, { useState } from "react"; import { X, Link2, Check } from "lucide-react"; import { getTranslations } from "./translations"; +import { useEditorStore } from "./editorStore"; interface ShareDialogProps { - open: boolean; onClose: () => void; - shareLink: string; language?: string; } -export function ShareDialog({ open, onClose, shareLink, language = "en" }: ShareDialogProps) { +export function ShareDialog({ onClose, language = "en" }: ShareDialogProps) { const t = getTranslations(language); const [copied, setCopied] = useState(false); + + // Get state from store + const open = useEditorStore(state => state.shareDialogOpen); + const shareLink = useEditorStore(state => state.shareLink); if (!open) return null; From 5317a942a9df6dea34e38b1b0b577c78e9e5143f Mon Sep 17 00:00:00 2001 From: Mike Barkmin Date: Mon, 13 Oct 2025 13:25:26 +0200 Subject: [PATCH 09/17] remove saved --- .../learningmap/src/LearningMapEditor.tsx | 27 +--- packages/learningmap/src/editorStore.ts | 115 +++++++++++------- 2 files changed, 74 insertions(+), 68 deletions(-) diff --git a/packages/learningmap/src/LearningMapEditor.tsx b/packages/learningmap/src/LearningMapEditor.tsx index 773b8d9..f8eff0c 100644 --- a/packages/learningmap/src/LearningMapEditor.tsx +++ b/packages/learningmap/src/LearningMapEditor.tsx @@ -68,12 +68,11 @@ export function LearningMapEditor({ const parsedRoadmap = parseRoadmapData(roadmapData || ""); const { screenToFlowPosition, zoomIn, zoomOut, setCenter, fitView } = useReactFlow(); - + // Only get minimal state needed in this component const nodes = useEditorStore(state => state.nodes); const edges = useEditorStore(state => state.edges); const settings = useEditorStore(state => state.settings); - const saved = useEditorStore(state => state.saved); const previewMode = useEditorStore(state => state.previewMode); const debugMode = useEditorStore(state => state.debugMode); const showGrid = useEditorStore(state => state.showGrid); @@ -88,12 +87,11 @@ export function LearningMapEditor({ const nextNodeId = useEditorStore(state => state.nextNodeId); const clipboard = useEditorStore(state => state.clipboard); const pendingExternalId = useEditorStore(state => state.pendingExternalId); - + // Store actions const onNodesChange = useEditorStore(state => state.onNodesChange); const onEdgesChange = useEditorStore(state => state.onEdgesChange); const onConnect = useEditorStore(state => state.onConnect); - const setSaved = useEditorStore(state => state.setSaved); const setHelpOpen = useEditorStore(state => state.setHelpOpen); const setShowGrid = useEditorStore(state => state.setShowGrid); const setSelectedNodeId = useEditorStore(state => state.setSelectedNodeId); @@ -123,7 +121,7 @@ export function LearningMapEditor({ const setNodes = useEditorStore(state => state.setNodes); const setEdges = useEditorStore(state => state.setEdges); const setSettings = useEditorStore(state => state.setSettings); - + // Temporal store for undo/redo const { undo, redo, canUndo, canRedo } = useTemporalStore(); @@ -166,7 +164,7 @@ export function LearningMapEditor({ // Filter out existing debug edges, but use the store's edges directly to avoid dependency loop const baseEdges = useEditorStore.getState().edges.filter((e) => !e.id.startsWith("debug-")); const newEdges: Edge[] = [...baseEdges]; - + if (debugMode) { nodes.forEach((node) => { if (showCompletionNeeds && node.type === "topic" && node.data?.completion?.needs) { @@ -331,7 +329,6 @@ export function LearningMapEditor({ const handleSave = useCallback(() => { const roadmapData = getRoadmapData(); - setSaved(true); if (onChange) { onChange(roadmapData); @@ -342,16 +339,7 @@ export function LearningMapEditor({ root.dispatchEvent(new CustomEvent("change", { detail: roadmapData })); } } - }, [nodes, edges, settings, onChange, getRoadmapData, setSaved]); - - // Auto-save when changes are made - useEffect(() => { - if (!saved) { - setTimeout(() => { - handleSave(); - }, 2000); - } - }, [saved, handleSave]); + }, [nodes, edges, settings, onChange, getRoadmapData]); const togglePreviewMode = useCallback(() => { handleSave(); @@ -380,7 +368,7 @@ export function LearningMapEditor({ const handleShare = useCallback(() => { const roadmapData = getRoadmapData(); - + // Check if map is empty (no nodes) if (!roadmapData.nodes || roadmapData.nodes.length === 0) { alert(t.emptyMapCannotBeShared); @@ -806,9 +794,6 @@ export function LearningMapEditor({ - {!saved && { handleSave(); }}> - - } {selectedNodeIds.length > 1 && } diff --git a/packages/learningmap/src/editorStore.ts b/packages/learningmap/src/editorStore.ts index 14985e7..7e4ba00 100644 --- a/packages/learningmap/src/editorStore.ts +++ b/packages/learningmap/src/editorStore.ts @@ -1,7 +1,22 @@ -import { create } from 'zustand'; -import { temporal } from 'zundo'; -import { Node, Edge, applyNodeChanges, applyEdgeChanges, addEdge, NodeChange, EdgeChange, Connection } from '@xyflow/react'; -import { NodeData, RoadmapData, Settings, ImageNodeData, TextNodeData } from './types'; +import { create } from "zustand"; +import { temporal } from "zundo"; +import { + Node, + Edge, + applyNodeChanges, + applyEdgeChanges, + addEdge, + NodeChange, + EdgeChange, + Connection, +} from "@xyflow/react"; +import { + NodeData, + RoadmapData, + Settings, + ImageNodeData, + TextNodeData, +} from "./types"; // Note: This is a global store for the editor. Typically only one editor instance is active at a time. // If you need multiple independent editor instances, consider creating store instances per component or using context. @@ -10,9 +25,8 @@ export interface EditorState { nodes: Node[]; edges: Edge[]; settings: Settings; - + // UI state - saved: boolean; previewMode: boolean; debugMode: boolean; showGrid: boolean; @@ -22,24 +36,24 @@ export interface EditorState { edgeDrawerOpen: boolean; shareDialogOpen: boolean; loadExternalDialogOpen: boolean; - + // Selected items selectedNodeId: string | null; selectedNodeIds: string[]; selectedEdge: Edge | null; - + // Other state nextNodeId: number; clipboard: { nodes: Node[]; edges: Edge[] } | null; lastMousePosition: { x: number; y: number } | null; shareLink: string; pendingExternalId: string | null; - + // Debug settings showCompletionNeeds: boolean; showCompletionOptional: boolean; showUnlockAfter: boolean; - + // Actions onNodesChange: (changes: NodeChange>[]) => void; onEdgesChange: (changes: EdgeChange[]) => void; @@ -54,9 +68,8 @@ export interface EditorState { deleteNode: (nodeId: string) => void; deleteEdge: (edgeId: string) => void; addNode: (node: Node) => void; - + // UI state setters - setSaved: (saved: boolean) => void; setPreviewMode: (previewMode: boolean) => void; setDebugMode: (debugMode: boolean) => void; setShowGrid: (showGrid: boolean) => void; @@ -70,14 +83,16 @@ export interface EditorState { setSelectedNodeIds: (nodeIds: string[]) => void; setSelectedEdge: (edge: Edge | null) => void; setNextNodeId: (nextNodeId: number) => void; - setClipboard: (clipboard: { nodes: Node[]; edges: Edge[] } | null) => void; + setClipboard: ( + clipboard: { nodes: Node[]; edges: Edge[] } | null, + ) => void; setLastMousePosition: (position: { x: number; y: number } | null) => void; setShareLink: (shareLink: string) => void; setPendingExternalId: (pendingExternalId: string | null) => void; setShowCompletionNeeds: (showCompletionNeeds: boolean) => void; setShowCompletionOptional: (showCompletionOptional: boolean) => void; setShowUnlockAfter: (showUnlockAfter: boolean) => void; - + // Bulk operations loadRoadmapData: (roadmapData: RoadmapData) => void; getRoadmapData: () => RoadmapData; @@ -89,7 +104,6 @@ const initialState = { nodes: [], edges: [], settings: { background: { color: "#ffffff" } }, - saved: true, previewMode: false, debugMode: false, showGrid: false, @@ -121,52 +135,47 @@ export const useEditorStore = create()( onNodesChange: (changes) => { set({ nodes: applyNodeChanges(changes, get().nodes), - saved: false, }); }, onEdgesChange: (changes) => { set({ edges: applyEdgeChanges(changes, get().edges), - saved: false, }); }, onConnect: (connection) => { set({ edges: addEdge(connection, get().edges), - saved: false, }); }, // Node operations setNodes: (nodes) => { - set({ nodes, saved: false }); + set({ nodes }); }, setEdges: (edges) => { - set({ edges, saved: false }); + set({ edges }); }, setSettings: (settings) => { - set({ settings, saved: false }); + set({ settings }); }, updateNode: (nodeId, updates) => { set({ nodes: get().nodes.map((n) => - n.id === nodeId ? { ...n, ...updates } : n + n.id === nodeId ? { ...n, ...updates } : n, ), - saved: false, }); }, updateNodeData: (nodeId, dataUpdates) => { set({ nodes: get().nodes.map((n) => - n.id === nodeId ? { ...n, data: { ...n.data, ...dataUpdates } } : n + n.id === nodeId ? { ...n, data: { ...n.data, ...dataUpdates } } : n, ), - saved: false, }); }, @@ -176,16 +185,14 @@ export const useEditorStore = create()( const updated = updates.find((un) => un.id === n.id); return updated ? updated : n; }), - saved: false, }); }, updateEdge: (edgeId, updates) => { set({ edges: get().edges.map((e) => - e.id === edgeId ? { ...e, ...updates } : e + e.id === edgeId ? { ...e, ...updates } : e, ), - saved: false, }); // Update selected edge if it's the one being updated const selectedEdge = get().selectedEdge; @@ -197,36 +204,36 @@ export const useEditorStore = create()( deleteNode: (nodeId) => { set({ nodes: get().nodes.filter((n) => n.id !== nodeId), - edges: get().edges.filter((e) => e.source !== nodeId && e.target !== nodeId), - saved: false, + edges: get().edges.filter( + (e) => e.source !== nodeId && e.target !== nodeId, + ), }); }, deleteEdge: (edgeId) => { set({ edges: get().edges.filter((e) => e.id !== edgeId), - saved: false, }); }, addNode: (node) => { set({ nodes: [...get().nodes, node], - saved: false, }); }, // UI state setters - setSaved: (saved) => set({ saved }), setPreviewMode: (previewMode) => set({ previewMode }), setDebugMode: (debugMode) => set({ debugMode }), setShowGrid: (showGrid) => set({ showGrid }), setHelpOpen: (helpOpen) => set({ helpOpen }), setDrawerOpen: (drawerOpen) => set({ drawerOpen }), - setSettingsDrawerOpen: (settingsDrawerOpen) => set({ settingsDrawerOpen }), + setSettingsDrawerOpen: (settingsDrawerOpen) => + set({ settingsDrawerOpen }), setEdgeDrawerOpen: (edgeDrawerOpen) => set({ edgeDrawerOpen }), setShareDialogOpen: (shareDialogOpen) => set({ shareDialogOpen }), - setLoadExternalDialogOpen: (loadExternalDialogOpen) => set({ loadExternalDialogOpen }), + setLoadExternalDialogOpen: (loadExternalDialogOpen) => + set({ loadExternalDialogOpen }), setSelectedNodeId: (selectedNodeId) => set({ selectedNodeId }), setSelectedNodeIds: (selectedNodeIds) => set({ selectedNodeIds }), setSelectedEdge: (selectedEdge) => set({ selectedEdge }), @@ -235,14 +242,20 @@ export const useEditorStore = create()( setLastMousePosition: (lastMousePosition) => set({ lastMousePosition }), setShareLink: (shareLink) => set({ shareLink }), setPendingExternalId: (pendingExternalId) => set({ pendingExternalId }), - setShowCompletionNeeds: (showCompletionNeeds) => set({ showCompletionNeeds }), - setShowCompletionOptional: (showCompletionOptional) => set({ showCompletionOptional }), + setShowCompletionNeeds: (showCompletionNeeds) => + set({ showCompletionNeeds }), + setShowCompletionOptional: (showCompletionOptional) => + set({ showCompletionOptional }), setShowUnlockAfter: (showUnlockAfter) => set({ showUnlockAfter }), // Bulk operations loadRoadmapData: (roadmapData) => { - const nodesArr = Array.isArray(roadmapData?.nodes) ? roadmapData.nodes : []; - const edgesArr = Array.isArray(roadmapData?.edges) ? roadmapData.edges : []; + const nodesArr = Array.isArray(roadmapData?.nodes) + ? roadmapData.nodes + : []; + const edgesArr = Array.isArray(roadmapData?.edges) + ? roadmapData.edges + : []; const rawNodes = nodesArr.map((n) => ({ ...n, @@ -257,7 +270,7 @@ export const useEditorStore = create()( const maxId = Math.max( ...nodesArr .map((n) => parseInt(n.id.replace(/\D/g, ""), 10)) - .filter((id) => !isNaN(id)) + .filter((id) => !isNaN(id)), ); nextNodeId = maxId + 1; } @@ -265,7 +278,9 @@ export const useEditorStore = create()( set({ nodes: rawNodes, edges: edgesArr, - settings: roadmapData?.settings || { background: { color: "#ffffff" } }, + settings: roadmapData?.settings || { + background: { color: "#ffffff" }, + }, nextNodeId, }); }, @@ -317,19 +332,25 @@ export const useEditorStore = create()( // Zundo options limit: 100, equality: (a, b) => a === b, - } - ) + }, + ), ); // Hook for accessing temporal store (undo/redo) -import { useStore } from 'zustand'; +import { useStore } from "zustand"; export const useTemporalStore = () => { const undo = useEditorStore.temporal.getState().undo; const redo = useEditorStore.temporal.getState().redo; - const pastStates = useStore(useEditorStore.temporal, (state) => state.pastStates); - const futureStates = useStore(useEditorStore.temporal, (state) => state.futureStates); - + const pastStates = useStore( + useEditorStore.temporal, + (state) => state.pastStates, + ); + const futureStates = useStore( + useEditorStore.temporal, + (state) => state.futureStates, + ); + return { undo, redo, From f614934adf976c767c53aa665241750b1ef89942 Mon Sep 17 00:00:00 2001 From: Mike Barkmin Date: Mon, 13 Oct 2025 13:33:47 +0200 Subject: [PATCH 10/17] add persist --- .../learningmap/src/LearningMapEditor.tsx | 40 +- packages/learningmap/src/editorStore.ts | 415 +++++++++--------- platforms/web/src/App.tsx | 27 +- 3 files changed, 217 insertions(+), 265 deletions(-) diff --git a/packages/learningmap/src/LearningMapEditor.tsx b/packages/learningmap/src/LearningMapEditor.tsx index f8eff0c..179253a 100644 --- a/packages/learningmap/src/LearningMapEditor.tsx +++ b/packages/learningmap/src/LearningMapEditor.tsx @@ -5,13 +5,11 @@ import { ColorMode, useReactFlow, Node, - Connection, Edge, Background, ControlButton, OnNodesChange, OnEdgesChange, - Panel, OnSelectionChangeFunc, ReactFlowProvider, } from "@xyflow/react"; @@ -21,13 +19,12 @@ import { TaskNode } from "./nodes/TaskNode"; import { TopicNode } from "./nodes/TopicNode"; import { ImageNode } from "./nodes/ImageNode"; import { TextNode } from "./nodes/TextNode"; -import { RoadmapData, NodeData, ImageNodeData, TextNodeData, Settings } from "./types"; +import { RoadmapData, NodeData, ImageNodeData, TextNodeData } from "./types"; import { SettingsDrawer } from "./SettingsDrawer"; import FloatingEdge from "./FloatingEdge"; import { EditorToolbar } from "./EditorToolbar"; -import { parseRoadmapData } from "./helper"; import { LearningMap } from "./LearningMap"; -import { Info, Redo, Undo, RotateCw, ShieldAlert, X } from "lucide-react"; +import { Info, Redo, Undo, RotateCw, X } from "lucide-react"; import { useEditorStore, useTemporalStore } from "./editorStore"; import { MultiNodePanel } from "./MultiNodePanel"; import { getTranslations } from "./translations"; @@ -49,7 +46,6 @@ const edgeTypes = { export interface LearningMapEditorProps { roadmapData?: string | RoadmapData; language?: string; - onChange?: (data: RoadmapData) => void; jsonStore?: string; } @@ -60,13 +56,9 @@ const getDefaultFilename = () => { }; export function LearningMapEditor({ - roadmapData, language = "en", - onChange, jsonStore = "https://json.openpatch.org", }: LearningMapEditorProps) { - - const parsedRoadmap = parseRoadmapData(roadmapData || ""); const { screenToFlowPosition, zoomIn, zoomOut, setCenter, fitView } = useReactFlow(); // Only get minimal state needed in this component @@ -156,10 +148,6 @@ export function LearningMapEditor({ { action: t.shortcuts.paste, shortcut: "Ctrl+V" }, ]; - useEffect(() => { - loadRoadmapData(parsedRoadmap); - }, [roadmapData, loadRoadmapData]); - useEffect(() => { // Filter out existing debug edges, but use the store's edges directly to avoid dependency loop const baseEdges = useEditorStore.getState().edges.filter((e) => !e.id.startsWith("debug-")); @@ -327,29 +315,14 @@ export function LearningMapEditor({ [nextNodeId, lastMousePosition, screenToFlowPosition, addNode, setNextNodeId, t] ); - const handleSave = useCallback(() => { - const roadmapData = getRoadmapData(); - - if (onChange) { - onChange(roadmapData); - return; - } else { - const root = document.querySelector("hyperbook-learningmap-editor"); - if (root) { - root.dispatchEvent(new CustomEvent("change", { detail: roadmapData })); - } - } - }, [nodes, edges, settings, onChange, getRoadmapData]); - const togglePreviewMode = useCallback(() => { - handleSave(); const newMode = !previewMode; setPreviewMode(newMode); if (newMode) { setDebugMode(false); closeDrawer(); } - }, [previewMode, setPreviewMode, setDebugMode, handleSave, closeDrawer]); + }, [previewMode, setPreviewMode, setDebugMode, closeDrawer]); const toggleDebugMode = useCallback(() => { setDebugMode(!debugMode); @@ -614,11 +587,6 @@ export function LearningMapEditor({ useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { - //save shortcut - if ((e.ctrlKey || e.metaKey) && e.key === 's' && !e.shiftKey) { - e.preventDefault(); - handleSave(); - } // undo shortcut if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) { e.preventDefault(); @@ -730,7 +698,7 @@ export function LearningMapEditor({ return () => { window.removeEventListener("keydown", handleKeyDown); }; - }, [handleSave, handleUndo, handleRedo, addNewNode, helpOpen, setHelpOpen, togglePreviewMode, toggleDebugMode, + }, [handleUndo, handleRedo, addNewNode, helpOpen, setHelpOpen, togglePreviewMode, toggleDebugMode, handleZoomIn, handleZoomOut, handleResetZoom, handleFitView, handleZoomToSelection, handleToggleGrid, handleResetMap, handleCut, handleCopy, handlePaste, handleSelectAll]); diff --git a/packages/learningmap/src/editorStore.ts b/packages/learningmap/src/editorStore.ts index 7e4ba00..aae30ac 100644 --- a/packages/learningmap/src/editorStore.ts +++ b/packages/learningmap/src/editorStore.ts @@ -1,5 +1,6 @@ import { create } from "zustand"; import { temporal } from "zundo"; +import { persist } from "zustand/middleware"; import { Node, Edge, @@ -10,13 +11,7 @@ import { EdgeChange, Connection, } from "@xyflow/react"; -import { - NodeData, - RoadmapData, - Settings, - ImageNodeData, - TextNodeData, -} from "./types"; +import { NodeData, RoadmapData, Settings } from "./types"; // Note: This is a global store for the editor. Typically only one editor instance is active at a time. // If you need multiple independent editor instances, consider creating store instances per component or using context. @@ -128,206 +123,218 @@ const initialState = { export const useEditorStore = create()( temporal( - (set, get) => ({ - ...initialState, - - // ReactFlow handlers - onNodesChange: (changes) => { - set({ - nodes: applyNodeChanges(changes, get().nodes), - }); - }, - - onEdgesChange: (changes) => { - set({ - edges: applyEdgeChanges(changes, get().edges), - }); - }, - - onConnect: (connection) => { - set({ - edges: addEdge(connection, get().edges), - }); - }, - - // Node operations - setNodes: (nodes) => { - set({ nodes }); - }, - - setEdges: (edges) => { - set({ edges }); - }, - - setSettings: (settings) => { - set({ settings }); - }, - - updateNode: (nodeId, updates) => { - set({ - nodes: get().nodes.map((n) => - n.id === nodeId ? { ...n, ...updates } : n, - ), - }); - }, - - updateNodeData: (nodeId, dataUpdates) => { - set({ - nodes: get().nodes.map((n) => - n.id === nodeId ? { ...n, data: { ...n.data, ...dataUpdates } } : n, - ), - }); - }, - - updateNodes: (updates) => { - set({ - nodes: get().nodes.map((n) => { - const updated = updates.find((un) => un.id === n.id); - return updated ? updated : n; - }), - }); - }, - - updateEdge: (edgeId, updates) => { - set({ - edges: get().edges.map((e) => - e.id === edgeId ? { ...e, ...updates } : e, - ), - }); - // Update selected edge if it's the one being updated - const selectedEdge = get().selectedEdge; - if (selectedEdge && selectedEdge.id === edgeId) { - set({ selectedEdge: { ...selectedEdge, ...updates } }); - } - }, - - deleteNode: (nodeId) => { - set({ - nodes: get().nodes.filter((n) => n.id !== nodeId), - edges: get().edges.filter( - (e) => e.source !== nodeId && e.target !== nodeId, - ), - }); - }, - - deleteEdge: (edgeId) => { - set({ - edges: get().edges.filter((e) => e.id !== edgeId), - }); - }, - - addNode: (node) => { - set({ - nodes: [...get().nodes, node], - }); - }, - - // UI state setters - setPreviewMode: (previewMode) => set({ previewMode }), - setDebugMode: (debugMode) => set({ debugMode }), - setShowGrid: (showGrid) => set({ showGrid }), - setHelpOpen: (helpOpen) => set({ helpOpen }), - setDrawerOpen: (drawerOpen) => set({ drawerOpen }), - setSettingsDrawerOpen: (settingsDrawerOpen) => - set({ settingsDrawerOpen }), - setEdgeDrawerOpen: (edgeDrawerOpen) => set({ edgeDrawerOpen }), - setShareDialogOpen: (shareDialogOpen) => set({ shareDialogOpen }), - setLoadExternalDialogOpen: (loadExternalDialogOpen) => - set({ loadExternalDialogOpen }), - setSelectedNodeId: (selectedNodeId) => set({ selectedNodeId }), - setSelectedNodeIds: (selectedNodeIds) => set({ selectedNodeIds }), - setSelectedEdge: (selectedEdge) => set({ selectedEdge }), - setNextNodeId: (nextNodeId) => set({ nextNodeId }), - setClipboard: (clipboard) => set({ clipboard }), - setLastMousePosition: (lastMousePosition) => set({ lastMousePosition }), - setShareLink: (shareLink) => set({ shareLink }), - setPendingExternalId: (pendingExternalId) => set({ pendingExternalId }), - setShowCompletionNeeds: (showCompletionNeeds) => - set({ showCompletionNeeds }), - setShowCompletionOptional: (showCompletionOptional) => - set({ showCompletionOptional }), - setShowUnlockAfter: (showUnlockAfter) => set({ showUnlockAfter }), - - // Bulk operations - loadRoadmapData: (roadmapData) => { - const nodesArr = Array.isArray(roadmapData?.nodes) - ? roadmapData.nodes - : []; - const edgesArr = Array.isArray(roadmapData?.edges) - ? roadmapData.edges - : []; - - const rawNodes = nodesArr.map((n) => ({ - ...n, - draggable: true, - className: n.data.color ? n.data.color : n.className, - data: { ...n.data }, - })); - - // Calculate next node ID - let nextNodeId = 1; - if (nodesArr.length > 0) { - const maxId = Math.max( - ...nodesArr - .map((n) => parseInt(n.id.replace(/\D/g, ""), 10)) - .filter((id) => !isNaN(id)), - ); - nextNodeId = maxId + 1; - } - - set({ - nodes: rawNodes, - edges: edgesArr, - settings: roadmapData?.settings || { - background: { color: "#ffffff" }, - }, - nextNodeId, - }); - }, - - getRoadmapData: () => { - const state = get(); - return { - nodes: state.nodes.map((n) => ({ - id: n.id, - type: n.type, - position: n.position, - width: n.width, - height: n.height, - zIndex: n.zIndex, - data: n.data, - })), - edges: state.edges - .filter((e) => !e.id.startsWith("debug-")) - .map((e) => ({ - id: e.id, - source: e.source, - target: e.target, - sourceHandle: e.sourceHandle, - targetHandle: e.targetHandle, - animated: e.animated, - type: e.type, - style: e.style, + persist( + (set, get) => ({ + ...initialState, + + // ReactFlow handlers + onNodesChange: (changes) => { + set({ + nodes: applyNodeChanges(changes, get().nodes), + }); + }, + + onEdgesChange: (changes) => { + set({ + edges: applyEdgeChanges(changes, get().edges), + }); + }, + + onConnect: (connection) => { + set({ + edges: addEdge(connection, get().edges), + }); + }, + + // Node operations + setNodes: (nodes) => { + set({ nodes }); + }, + + setEdges: (edges) => { + set({ edges }); + }, + + setSettings: (settings) => { + set({ settings }); + }, + + updateNode: (nodeId, updates) => { + set({ + nodes: get().nodes.map((n) => + n.id === nodeId ? { ...n, ...updates } : n, + ), + }); + }, + + updateNodeData: (nodeId, dataUpdates) => { + set({ + nodes: get().nodes.map((n) => + n.id === nodeId + ? { ...n, data: { ...n.data, ...dataUpdates } } + : n, + ), + }); + }, + + updateNodes: (updates) => { + set({ + nodes: get().nodes.map((n) => { + const updated = updates.find((un) => un.id === n.id); + return updated ? updated : n; + }), + }); + }, + + updateEdge: (edgeId, updates) => { + set({ + edges: get().edges.map((e) => + e.id === edgeId ? { ...e, ...updates } : e, + ), + }); + // Update selected edge if it's the one being updated + const selectedEdge = get().selectedEdge; + if (selectedEdge && selectedEdge.id === edgeId) { + set({ selectedEdge: { ...selectedEdge, ...updates } }); + } + }, + + deleteNode: (nodeId) => { + set({ + nodes: get().nodes.filter((n) => n.id !== nodeId), + edges: get().edges.filter( + (e) => e.source !== nodeId && e.target !== nodeId, + ), + }); + }, + + deleteEdge: (edgeId) => { + set({ + edges: get().edges.filter((e) => e.id !== edgeId), + }); + }, + + addNode: (node) => { + set({ + nodes: [...get().nodes, node], + }); + }, + + // UI state setters + setPreviewMode: (previewMode) => set({ previewMode }), + setDebugMode: (debugMode) => set({ debugMode }), + setShowGrid: (showGrid) => set({ showGrid }), + setHelpOpen: (helpOpen) => set({ helpOpen }), + setDrawerOpen: (drawerOpen) => set({ drawerOpen }), + setSettingsDrawerOpen: (settingsDrawerOpen) => + set({ settingsDrawerOpen }), + setEdgeDrawerOpen: (edgeDrawerOpen) => set({ edgeDrawerOpen }), + setShareDialogOpen: (shareDialogOpen) => set({ shareDialogOpen }), + setLoadExternalDialogOpen: (loadExternalDialogOpen) => + set({ loadExternalDialogOpen }), + setSelectedNodeId: (selectedNodeId) => set({ selectedNodeId }), + setSelectedNodeIds: (selectedNodeIds) => set({ selectedNodeIds }), + setSelectedEdge: (selectedEdge) => set({ selectedEdge }), + setNextNodeId: (nextNodeId) => set({ nextNodeId }), + setClipboard: (clipboard) => set({ clipboard }), + setLastMousePosition: (lastMousePosition) => set({ lastMousePosition }), + setShareLink: (shareLink) => set({ shareLink }), + setPendingExternalId: (pendingExternalId) => set({ pendingExternalId }), + setShowCompletionNeeds: (showCompletionNeeds) => + set({ showCompletionNeeds }), + setShowCompletionOptional: (showCompletionOptional) => + set({ showCompletionOptional }), + setShowUnlockAfter: (showUnlockAfter) => set({ showUnlockAfter }), + + // Bulk operations + loadRoadmapData: (roadmapData) => { + const nodesArr = Array.isArray(roadmapData?.nodes) + ? roadmapData.nodes + : []; + const edgesArr = Array.isArray(roadmapData?.edges) + ? roadmapData.edges + : []; + + const rawNodes = nodesArr.map((n) => ({ + ...n, + draggable: true, + className: n.data.color ? n.data.color : n.className, + data: { ...n.data }, + })); + + // Calculate next node ID + let nextNodeId = 1; + if (nodesArr.length > 0) { + const maxId = Math.max( + ...nodesArr + .map((n) => parseInt(n.id.replace(/\D/g, ""), 10)) + .filter((id) => !isNaN(id)), + ); + nextNodeId = maxId + 1; + } + + set({ + nodes: rawNodes, + edges: edgesArr, + settings: roadmapData?.settings || { + background: { color: "#ffffff" }, + }, + nextNodeId, + }); + }, + + getRoadmapData: () => { + const state = get(); + return { + nodes: state.nodes.map((n) => ({ + id: n.id, + type: n.type, + position: n.position, + width: n.width, + height: n.height, + zIndex: n.zIndex, + data: n.data, })), + edges: state.edges + .filter((e) => !e.id.startsWith("debug-")) + .map((e) => ({ + id: e.id, + source: e.source, + target: e.target, + sourceHandle: e.sourceHandle, + targetHandle: e.targetHandle, + animated: e.animated, + type: e.type, + style: e.style, + })), + settings: state.settings, + version: 1, + }; + }, + + closeAllDrawers: () => { + set({ + drawerOpen: false, + selectedNodeId: null, + edgeDrawerOpen: false, + selectedEdge: null, + settingsDrawerOpen: false, + }); + }, + + reset: () => { + set(initialState); + }, + }), + { + name: "roadmap-data", + partialize: (state) => ({ + nodes: state.nodes, + edges: state.edges, settings: state.settings, - version: 1, - }; - }, - - closeAllDrawers: () => { - set({ - drawerOpen: false, - selectedNodeId: null, - edgeDrawerOpen: false, - selectedEdge: null, - settingsDrawerOpen: false, - }); - }, - - reset: () => { - set(initialState); + }), }, - }), + ), { // Zundo options limit: 100, diff --git a/platforms/web/src/App.tsx b/platforms/web/src/App.tsx index b0e6902..a3d859a 100644 --- a/platforms/web/src/App.tsx +++ b/platforms/web/src/App.tsx @@ -1,34 +1,11 @@ import './App.css' -import { LearningMapEditor, type LearningMapEditorProps } from '@learningmap/learningmap'; +import { LearningMapEditor } from '@learningmap/learningmap'; import "@learningmap/learningmap/index.css"; -import { useEffect, useState } from 'react'; function App() { - const [roadmapData, setRoadmapData] = useState(undefined); - - useEffect(() => { - // Don't load from localStorage if loading from external source - const hash = window.location.hash; - if (hash.startsWith("#json=")) { - return; - } - - const savedState = localStorage.getItem("learningmap-editor-state"); - if (savedState) { - const state = JSON.parse(savedState); - setRoadmapData(state); - } - }, []); - - const handleChange: LearningMapEditorProps["onChange"] = (state) => { - localStorage.setItem("learningmap-editor-state", JSON.stringify(state)); - } - return ( - ) From 5f56d00c1711c31a0059f60ce8ef0d529a775564 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 11:43:03 +0000 Subject: [PATCH 11/17] Refactor: Split LearningMapEditor into smaller components for better performance Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- packages/learningmap/src/DebugModeEdges.tsx | 67 ++ packages/learningmap/src/EditorCanvas.tsx | 134 +++ packages/learningmap/src/EditorDialogs.tsx | 84 ++ .../learningmap/src/KeyboardShortcuts.tsx | 133 +++ .../learningmap/src/LearningMapEditor.tsx | 65 +- .../src/LearningMapEditor.tsx.backup | 899 ++++++++++++++++++ packages/learningmap/src/editorStore.ts | 432 ++++----- packages/learningmap/src/useEditorActions.ts | 415 ++++++++ 8 files changed, 1990 insertions(+), 239 deletions(-) create mode 100644 packages/learningmap/src/DebugModeEdges.tsx create mode 100644 packages/learningmap/src/EditorCanvas.tsx create mode 100644 packages/learningmap/src/EditorDialogs.tsx create mode 100644 packages/learningmap/src/KeyboardShortcuts.tsx create mode 100644 packages/learningmap/src/LearningMapEditor.tsx.backup create mode 100644 packages/learningmap/src/useEditorActions.ts diff --git a/packages/learningmap/src/DebugModeEdges.tsx b/packages/learningmap/src/DebugModeEdges.tsx new file mode 100644 index 0000000..acb7399 --- /dev/null +++ b/packages/learningmap/src/DebugModeEdges.tsx @@ -0,0 +1,67 @@ +import { useEffect } from "react"; +import { Edge } from "@xyflow/react"; +import { useEditorStore } from "./editorStore"; + +export const DebugModeEdges = () => { + const nodes = useEditorStore(state => state.nodes); + const debugMode = useEditorStore(state => state.debugMode); + const showCompletionNeeds = useEditorStore(state => state.showCompletionNeeds); + const showCompletionOptional = useEditorStore(state => state.showCompletionOptional); + const showUnlockAfter = useEditorStore(state => state.showUnlockAfter); + const setEdges = useEditorStore(state => state.setEdges); + + useEffect(() => { + // Filter out existing debug edges, but use the store's edges directly to avoid dependency loop + const baseEdges = useEditorStore.getState().edges.filter((e) => !e.id.startsWith("debug-")); + const newEdges: Edge[] = [...baseEdges]; + + if (debugMode) { + nodes.forEach((node) => { + if (showCompletionNeeds && node.type === "topic" && node.data?.completion?.needs) { + node.data.completion.needs.forEach((needId: string) => { + const edgeId = `debug-edge-${needId}-to-${node.id}`; + newEdges.push({ + id: edgeId, + target: needId, + source: node.id, + animated: true, + style: { stroke: "#f97316", strokeWidth: 2, strokeDasharray: "5,5" }, + type: "floating", + }); + }); + } + if (showCompletionOptional && node.data?.completion?.optional) { + node.data.completion.optional.forEach((optionalId: string) => { + const edgeId = `debug-edge-optional-${optionalId}-to-${node.id}`; + newEdges.push({ + id: edgeId, + target: optionalId, + source: node.id, + animated: true, + style: { stroke: "#eab308", strokeWidth: 2, strokeDasharray: "5,5" }, + type: "floating", + }); + }); + } + }); + nodes.forEach((node) => { + if (showUnlockAfter && node.data.unlock?.after) { + node.data.unlock.after.forEach((unlockId: string) => { + const edgeId = `debug-edge-${unlockId}-to-${node.id}`; + newEdges.push({ + id: edgeId, + target: unlockId, + source: node.id, + animated: true, + style: { stroke: "#10b981", strokeWidth: 2, strokeDasharray: "5,5" }, + type: "floating", + }); + }); + } + }); + } + setEdges(newEdges); + }, [nodes, debugMode, showCompletionNeeds, showCompletionOptional, showUnlockAfter, setEdges]); + + return null; +}; diff --git a/packages/learningmap/src/EditorCanvas.tsx b/packages/learningmap/src/EditorCanvas.tsx new file mode 100644 index 0000000..e3ca6a2 --- /dev/null +++ b/packages/learningmap/src/EditorCanvas.tsx @@ -0,0 +1,134 @@ +import React, { useCallback, memo } from "react"; +import { ReactFlow, Controls, Background, ControlButton, Panel, OnNodesChange, OnEdgesChange, OnSelectionChangeFunc } from "@xyflow/react"; +import { Info, Redo, Undo, RotateCw, ShieldAlert } from "lucide-react"; +import { useEditorStore, useTemporalStore } from "./editorStore"; +import { TaskNode } from "./nodes/TaskNode"; +import { TopicNode } from "./nodes/TopicNode"; +import { ImageNode } from "./nodes/ImageNode"; +import { TextNode } from "./nodes/TextNode"; +import FloatingEdge from "./FloatingEdge"; +import { MultiNodePanel } from "./MultiNodePanel"; +import { getTranslations } from "./translations"; + +const nodeTypes = { + topic: TopicNode, + task: TaskNode, + image: ImageNode, + text: TextNode, +}; + +const edgeTypes = { + floating: FloatingEdge +}; + +interface EditorCanvasProps { + onNodeClick: (event: any, node: any) => void; + onEdgeClick: (event: any, edge: any) => void; + onSave: () => void; + language?: string; +} + +export const EditorCanvas = memo(({ onNodeClick, onEdgeClick, onSave, language = "en" }: EditorCanvasProps) => { + const t = getTranslations(language); + + // Get state from store + const nodes = useEditorStore(state => state.nodes); + const edges = useEditorStore(state => state.edges); + const settings = useEditorStore(state => state.settings); + const showGrid = useEditorStore(state => state.showGrid); + const selectedNodeIds = useEditorStore(state => state.selectedNodeIds); + + // Get actions from store + const onNodesChange = useEditorStore(state => state.onNodesChange); + const onEdgesChange = useEditorStore(state => state.onEdgesChange); + const onConnect = useEditorStore(state => state.onConnect); + const setSelectedNodeIds = useEditorStore(state => state.setSelectedNodeIds); + const setHelpOpen = useEditorStore(state => state.setHelpOpen); + const updateNodes = useEditorStore(state => state.updateNodes); + + // Temporal store for undo/redo + const { undo, redo, canUndo, canRedo } = useTemporalStore(); + + const handleNodesChange: OnNodesChange = useCallback( + (changes) => { + onNodesChange(changes); + }, + [onNodesChange] + ); + + const handleEdgesChange: OnEdgesChange = useCallback( + (changes) => { + onEdgesChange(changes); + }, + [onEdgesChange] + ); + + const handleSelectionChange: OnSelectionChangeFunc = useCallback( + ({ nodes: selectedNodes }) => { + setSelectedNodeIds(selectedNodes.map(n => n.id)); + }, + [setSelectedNodeIds] + ); + + const handleUpdateNodes = useCallback( + (updatedNodes: any[]) => { + updateNodes(updatedNodes); + }, + [updateNodes] + ); + + const defaultEdgeOptions = { + animated: false, + style: { + stroke: "#94a3b8", + strokeWidth: 2, + }, + type: "default", + }; + + return ( +
+ + {showGrid && } + + undo()}> + + + redo()}> + + + setHelpOpen(true)}> + + + + {selectedNodeIds.length > 1 && } + +
+ ); +}); + +EditorCanvas.displayName = 'EditorCanvas'; diff --git a/packages/learningmap/src/EditorDialogs.tsx b/packages/learningmap/src/EditorDialogs.tsx new file mode 100644 index 0000000..372218c --- /dev/null +++ b/packages/learningmap/src/EditorDialogs.tsx @@ -0,0 +1,84 @@ +import React, { memo } from "react"; +import { X } from "lucide-react"; +import { useEditorStore } from "./editorStore"; +import { ShareDialog } from "./ShareDialog"; +import { LoadExternalDialog } from "./LoadExternalDialog"; +import { getTranslations } from "./translations"; + +interface EditorDialogsProps { + onDownload: () => void; + onLoadFromStore: (id: string) => void; + language?: string; + keyboardShortcuts: Array<{ action: string; shortcut: string }>; +} + +export const EditorDialogs = memo(({ onDownload, onLoadFromStore, language = "en", keyboardShortcuts }: EditorDialogsProps) => { + const t = getTranslations(language); + + // Get state from store + const helpOpen = useEditorStore(state => state.helpOpen); + const pendingExternalId = useEditorStore(state => state.pendingExternalId); + + // Get actions from store + const setHelpOpen = useEditorStore(state => state.setHelpOpen); + const setShareDialogOpen = useEditorStore(state => state.setShareDialogOpen); + const setLoadExternalDialogOpen = useEditorStore(state => state.setLoadExternalDialogOpen); + const setPendingExternalId = useEditorStore(state => state.setPendingExternalId); + + return ( + <> + setHelpOpen(false)} + > +
+

{t.keyboardShortcuts}

+ +
+
+ + + + + + + + + {keyboardShortcuts.map((item) => ( + + + + + ))} + +
{t.action}{t.shortcut}
{item.action}{item.shortcut}
+
+
+ +
+
+ setShareDialogOpen(false)} + language={language} + /> + { + setLoadExternalDialogOpen(false); + setPendingExternalId(null); + }} + onDownloadCurrent={onDownload} + onReplace={() => { + if (pendingExternalId) { + onLoadFromStore(pendingExternalId); + } + }} + language={language} + /> + + ); +}); + +EditorDialogs.displayName = 'EditorDialogs'; diff --git a/packages/learningmap/src/KeyboardShortcuts.tsx b/packages/learningmap/src/KeyboardShortcuts.tsx new file mode 100644 index 0000000..c3a562e --- /dev/null +++ b/packages/learningmap/src/KeyboardShortcuts.tsx @@ -0,0 +1,133 @@ +import { useEffect } from "react"; +import { useReactFlow } from "@xyflow/react"; +import { useEditorStore } from "./editorStore"; + +interface KeyboardShortcutsProps { + onAddNode: (type: "task" | "topic" | "image" | "text") => void; + onDeleteSelected: () => void; + onSave: () => void; + onUndo: () => void; + onRedo: () => void; + onTogglePreview: () => void; + onToggleDebug: () => void; + onResetMap: () => void; + onCut: () => void; + onCopy: () => void; + onPaste: () => void; + onSelectAll: () => void; + onZoomIn: () => void; + onZoomOut: () => void; + onResetZoom: () => void; + onFitView: () => void; + onZoomToSelection: () => void; + onToggleGrid: () => void; +} + +export const KeyboardShortcuts = ({ + onAddNode, + onDeleteSelected, + onSave, + onUndo, + onRedo, + onTogglePreview, + onToggleDebug, + onResetMap, + onCut, + onCopy, + onPaste, + onSelectAll, + onZoomIn, + onZoomOut, + onResetZoom, + onFitView, + onZoomToSelection, + onToggleGrid, +}: KeyboardShortcutsProps) => { + const setHelpOpen = useEditorStore(state => state.setHelpOpen); + const helpOpen = useEditorStore(state => state.helpOpen); + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.ctrlKey || e.metaKey) { + if (e.key === '1') { + e.preventDefault(); + onAddNode("task"); + } else if (e.key === '2') { + e.preventDefault(); + onAddNode("topic"); + } else if (e.key === '3') { + e.preventDefault(); + onAddNode("image"); + } else if (e.key === '4') { + e.preventDefault(); + onAddNode("text"); + } else if (e.key === 's') { + e.preventDefault(); + onSave(); + } else if (e.key === 'z' && !e.shiftKey) { + e.preventDefault(); + onUndo(); + } else if ((e.key === 'y') || (e.key === 'z' && e.shiftKey)) { + e.preventDefault(); + onRedo(); + } else if ((e.key === '?' || (e.shiftKey && e.key === '/'))) { + e.preventDefault(); + setHelpOpen(!helpOpen); + } else if (e.key.toLowerCase() === 'p' && !e.shiftKey) { + e.preventDefault(); + onTogglePreview(); + } else if (e.key.toLowerCase() === 'd' && !e.shiftKey) { + e.preventDefault(); + onToggleDebug(); + } else if (e.key === '+' || e.key === '=') { + e.preventDefault(); + onZoomIn(); + } else if (e.key === '-') { + e.preventDefault(); + onZoomOut(); + } else if (e.key === '0') { + e.preventDefault(); + onResetZoom(); + } else if (e.key === "'") { + e.preventDefault(); + onToggleGrid(); + } else if (e.key === 'Delete') { + e.preventDefault(); + onResetMap(); + } else if (e.key.toLowerCase() === 'x') { + e.preventDefault(); + onCut(); + } else if (e.key.toLowerCase() === 'c') { + e.preventDefault(); + onCopy(); + } else if (e.key.toLowerCase() === 'v') { + e.preventDefault(); + onPaste(); + } else if (e.key.toLowerCase() === 'a') { + e.preventDefault(); + onSelectAll(); + } + } else if (e.shiftKey) { + if (e.key === '!') { + e.preventDefault(); + onFitView(); + } else if (e.key === '@') { + e.preventDefault(); + onZoomToSelection(); + } + } else if (e.key === 'Delete') { + e.preventDefault(); + onDeleteSelected(); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => { + window.removeEventListener("keydown", handleKeyDown); + }; + }, [onAddNode, onDeleteSelected, onSave, onUndo, onRedo, helpOpen, setHelpOpen, onTogglePreview, onToggleDebug, + onZoomIn, onZoomOut, onResetZoom, onFitView, onZoomToSelection, onToggleGrid, + onResetMap, onCut, onCopy, onPaste, onSelectAll]); + + return null; +}; diff --git a/packages/learningmap/src/LearningMapEditor.tsx b/packages/learningmap/src/LearningMapEditor.tsx index 179253a..773b8d9 100644 --- a/packages/learningmap/src/LearningMapEditor.tsx +++ b/packages/learningmap/src/LearningMapEditor.tsx @@ -5,11 +5,13 @@ import { ColorMode, useReactFlow, Node, + Connection, Edge, Background, ControlButton, OnNodesChange, OnEdgesChange, + Panel, OnSelectionChangeFunc, ReactFlowProvider, } from "@xyflow/react"; @@ -19,12 +21,13 @@ import { TaskNode } from "./nodes/TaskNode"; import { TopicNode } from "./nodes/TopicNode"; import { ImageNode } from "./nodes/ImageNode"; import { TextNode } from "./nodes/TextNode"; -import { RoadmapData, NodeData, ImageNodeData, TextNodeData } from "./types"; +import { RoadmapData, NodeData, ImageNodeData, TextNodeData, Settings } from "./types"; import { SettingsDrawer } from "./SettingsDrawer"; import FloatingEdge from "./FloatingEdge"; import { EditorToolbar } from "./EditorToolbar"; +import { parseRoadmapData } from "./helper"; import { LearningMap } from "./LearningMap"; -import { Info, Redo, Undo, RotateCw, X } from "lucide-react"; +import { Info, Redo, Undo, RotateCw, ShieldAlert, X } from "lucide-react"; import { useEditorStore, useTemporalStore } from "./editorStore"; import { MultiNodePanel } from "./MultiNodePanel"; import { getTranslations } from "./translations"; @@ -46,6 +49,7 @@ const edgeTypes = { export interface LearningMapEditorProps { roadmapData?: string | RoadmapData; language?: string; + onChange?: (data: RoadmapData) => void; jsonStore?: string; } @@ -56,15 +60,20 @@ const getDefaultFilename = () => { }; export function LearningMapEditor({ + roadmapData, language = "en", + onChange, jsonStore = "https://json.openpatch.org", }: LearningMapEditorProps) { - const { screenToFlowPosition, zoomIn, zoomOut, setCenter, fitView } = useReactFlow(); + const parsedRoadmap = parseRoadmapData(roadmapData || ""); + const { screenToFlowPosition, zoomIn, zoomOut, setCenter, fitView } = useReactFlow(); + // Only get minimal state needed in this component const nodes = useEditorStore(state => state.nodes); const edges = useEditorStore(state => state.edges); const settings = useEditorStore(state => state.settings); + const saved = useEditorStore(state => state.saved); const previewMode = useEditorStore(state => state.previewMode); const debugMode = useEditorStore(state => state.debugMode); const showGrid = useEditorStore(state => state.showGrid); @@ -79,11 +88,12 @@ export function LearningMapEditor({ const nextNodeId = useEditorStore(state => state.nextNodeId); const clipboard = useEditorStore(state => state.clipboard); const pendingExternalId = useEditorStore(state => state.pendingExternalId); - + // Store actions const onNodesChange = useEditorStore(state => state.onNodesChange); const onEdgesChange = useEditorStore(state => state.onEdgesChange); const onConnect = useEditorStore(state => state.onConnect); + const setSaved = useEditorStore(state => state.setSaved); const setHelpOpen = useEditorStore(state => state.setHelpOpen); const setShowGrid = useEditorStore(state => state.setShowGrid); const setSelectedNodeId = useEditorStore(state => state.setSelectedNodeId); @@ -113,7 +123,7 @@ export function LearningMapEditor({ const setNodes = useEditorStore(state => state.setNodes); const setEdges = useEditorStore(state => state.setEdges); const setSettings = useEditorStore(state => state.setSettings); - + // Temporal store for undo/redo const { undo, redo, canUndo, canRedo } = useTemporalStore(); @@ -148,11 +158,15 @@ export function LearningMapEditor({ { action: t.shortcuts.paste, shortcut: "Ctrl+V" }, ]; + useEffect(() => { + loadRoadmapData(parsedRoadmap); + }, [roadmapData, loadRoadmapData]); + useEffect(() => { // Filter out existing debug edges, but use the store's edges directly to avoid dependency loop const baseEdges = useEditorStore.getState().edges.filter((e) => !e.id.startsWith("debug-")); const newEdges: Edge[] = [...baseEdges]; - + if (debugMode) { nodes.forEach((node) => { if (showCompletionNeeds && node.type === "topic" && node.data?.completion?.needs) { @@ -315,14 +329,39 @@ export function LearningMapEditor({ [nextNodeId, lastMousePosition, screenToFlowPosition, addNode, setNextNodeId, t] ); + const handleSave = useCallback(() => { + const roadmapData = getRoadmapData(); + setSaved(true); + + if (onChange) { + onChange(roadmapData); + return; + } else { + const root = document.querySelector("hyperbook-learningmap-editor"); + if (root) { + root.dispatchEvent(new CustomEvent("change", { detail: roadmapData })); + } + } + }, [nodes, edges, settings, onChange, getRoadmapData, setSaved]); + + // Auto-save when changes are made + useEffect(() => { + if (!saved) { + setTimeout(() => { + handleSave(); + }, 2000); + } + }, [saved, handleSave]); + const togglePreviewMode = useCallback(() => { + handleSave(); const newMode = !previewMode; setPreviewMode(newMode); if (newMode) { setDebugMode(false); closeDrawer(); } - }, [previewMode, setPreviewMode, setDebugMode, closeDrawer]); + }, [previewMode, setPreviewMode, setDebugMode, handleSave, closeDrawer]); const toggleDebugMode = useCallback(() => { setDebugMode(!debugMode); @@ -341,7 +380,7 @@ export function LearningMapEditor({ const handleShare = useCallback(() => { const roadmapData = getRoadmapData(); - + // Check if map is empty (no nodes) if (!roadmapData.nodes || roadmapData.nodes.length === 0) { alert(t.emptyMapCannotBeShared); @@ -587,6 +626,11 @@ export function LearningMapEditor({ useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { + //save shortcut + if ((e.ctrlKey || e.metaKey) && e.key === 's' && !e.shiftKey) { + e.preventDefault(); + handleSave(); + } // undo shortcut if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) { e.preventDefault(); @@ -698,7 +742,7 @@ export function LearningMapEditor({ return () => { window.removeEventListener("keydown", handleKeyDown); }; - }, [handleUndo, handleRedo, addNewNode, helpOpen, setHelpOpen, togglePreviewMode, toggleDebugMode, + }, [handleSave, handleUndo, handleRedo, addNewNode, helpOpen, setHelpOpen, togglePreviewMode, toggleDebugMode, handleZoomIn, handleZoomOut, handleResetZoom, handleFitView, handleZoomToSelection, handleToggleGrid, handleResetMap, handleCut, handleCopy, handlePaste, handleSelectAll]); @@ -762,6 +806,9 @@ export function LearningMapEditor({ + {!saved && { handleSave(); }}> + + } {selectedNodeIds.length > 1 && } diff --git a/packages/learningmap/src/LearningMapEditor.tsx.backup b/packages/learningmap/src/LearningMapEditor.tsx.backup new file mode 100644 index 0000000..773b8d9 --- /dev/null +++ b/packages/learningmap/src/LearningMapEditor.tsx.backup @@ -0,0 +1,899 @@ +import { useCallback, useEffect } from "react"; +import { + ReactFlow, + Controls, + ColorMode, + useReactFlow, + Node, + Connection, + Edge, + Background, + ControlButton, + OnNodesChange, + OnEdgesChange, + Panel, + OnSelectionChangeFunc, + ReactFlowProvider, +} from "@xyflow/react"; +import { EditorDrawer } from "./EditorDrawer"; +import { EdgeDrawer } from "./EdgeDrawer"; +import { TaskNode } from "./nodes/TaskNode"; +import { TopicNode } from "./nodes/TopicNode"; +import { ImageNode } from "./nodes/ImageNode"; +import { TextNode } from "./nodes/TextNode"; +import { RoadmapData, NodeData, ImageNodeData, TextNodeData, Settings } from "./types"; +import { SettingsDrawer } from "./SettingsDrawer"; +import FloatingEdge from "./FloatingEdge"; +import { EditorToolbar } from "./EditorToolbar"; +import { parseRoadmapData } from "./helper"; +import { LearningMap } from "./LearningMap"; +import { Info, Redo, Undo, RotateCw, ShieldAlert, X } from "lucide-react"; +import { useEditorStore, useTemporalStore } from "./editorStore"; +import { MultiNodePanel } from "./MultiNodePanel"; +import { getTranslations } from "./translations"; +import { WelcomeMessage } from "./WelcomeMessage"; +import { ShareDialog } from "./ShareDialog"; +import { LoadExternalDialog } from "./LoadExternalDialog"; + +const nodeTypes = { + topic: TopicNode, + task: TaskNode, + image: ImageNode, + text: TextNode, +}; + +const edgeTypes = { + floating: FloatingEdge +}; + +export interface LearningMapEditorProps { + roadmapData?: string | RoadmapData; + language?: string; + onChange?: (data: RoadmapData) => void; + jsonStore?: string; +} + +const getDefaultFilename = () => { + const now = new Date(); + const pad = (n: number) => n.toString().padStart(2, '0'); + return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}`; +}; + +export function LearningMapEditor({ + roadmapData, + language = "en", + onChange, + jsonStore = "https://json.openpatch.org", +}: LearningMapEditorProps) { + + const parsedRoadmap = parseRoadmapData(roadmapData || ""); + const { screenToFlowPosition, zoomIn, zoomOut, setCenter, fitView } = useReactFlow(); + + // Only get minimal state needed in this component + const nodes = useEditorStore(state => state.nodes); + const edges = useEditorStore(state => state.edges); + const settings = useEditorStore(state => state.settings); + const saved = useEditorStore(state => state.saved); + const previewMode = useEditorStore(state => state.previewMode); + const debugMode = useEditorStore(state => state.debugMode); + const showGrid = useEditorStore(state => state.showGrid); + const helpOpen = useEditorStore(state => state.helpOpen); + const selectedNodeId = useEditorStore(state => state.selectedNodeId); + const selectedNodeIds = useEditorStore(state => state.selectedNodeIds); + const selectedEdge = useEditorStore(state => state.selectedEdge); + const showCompletionNeeds = useEditorStore(state => state.showCompletionNeeds); + const showCompletionOptional = useEditorStore(state => state.showCompletionOptional); + const showUnlockAfter = useEditorStore(state => state.showUnlockAfter); + const lastMousePosition = useEditorStore(state => state.lastMousePosition); + const nextNodeId = useEditorStore(state => state.nextNodeId); + const clipboard = useEditorStore(state => state.clipboard); + const pendingExternalId = useEditorStore(state => state.pendingExternalId); + + // Store actions + const onNodesChange = useEditorStore(state => state.onNodesChange); + const onEdgesChange = useEditorStore(state => state.onEdgesChange); + const onConnect = useEditorStore(state => state.onConnect); + const setSaved = useEditorStore(state => state.setSaved); + const setHelpOpen = useEditorStore(state => state.setHelpOpen); + const setShowGrid = useEditorStore(state => state.setShowGrid); + const setSelectedNodeId = useEditorStore(state => state.setSelectedNodeId); + const setSelectedNodeIds = useEditorStore(state => state.setSelectedNodeIds); + const setDrawerOpen = useEditorStore(state => state.setDrawerOpen); + const setSettingsDrawerOpen = useEditorStore(state => state.setSettingsDrawerOpen); + const setEdgeDrawerOpen = useEditorStore(state => state.setEdgeDrawerOpen); + const setSelectedEdge = useEditorStore(state => state.setSelectedEdge); + const setNextNodeId = useEditorStore(state => state.setNextNodeId); + const setClipboard = useEditorStore(state => state.setClipboard); + const setLastMousePosition = useEditorStore(state => state.setLastMousePosition); + const setShareDialogOpen = useEditorStore(state => state.setShareDialogOpen); + const setLoadExternalDialogOpen = useEditorStore(state => state.setLoadExternalDialogOpen); + const setPendingExternalId = useEditorStore(state => state.setPendingExternalId); + const setShareLink = useEditorStore(state => state.setShareLink); + const setDebugMode = useEditorStore(state => state.setDebugMode); + const setPreviewMode = useEditorStore(state => state.setPreviewMode); + const updateNode = useEditorStore(state => state.updateNode); + const updateNodes = useEditorStore(state => state.updateNodes); + const updateEdge = useEditorStore(state => state.updateEdge); + const deleteNode = useEditorStore(state => state.deleteNode); + const deleteEdge = useEditorStore(state => state.deleteEdge); + const addNode = useEditorStore(state => state.addNode); + const loadRoadmapData = useEditorStore(state => state.loadRoadmapData); + const getRoadmapData = useEditorStore(state => state.getRoadmapData); + const closeAllDrawers = useEditorStore(state => state.closeAllDrawers); + const setNodes = useEditorStore(state => state.setNodes); + const setEdges = useEditorStore(state => state.setEdges); + const setSettings = useEditorStore(state => state.setSettings); + + // Temporal store for undo/redo + const { undo, redo, canUndo, canRedo } = useTemporalStore(); + + const colorMode: ColorMode = "light"; + + // Use language from settings if available, otherwise use prop + const effectiveLanguage = settings?.language || language; + const t = getTranslations(effectiveLanguage); + + const keyboardShortcuts = [ + { action: t.shortcuts.undo, shortcut: "Ctrl+Z" }, + { action: t.shortcuts.redo, shortcut: "Ctrl+Y or Ctrl+Shift+Z" }, + { action: t.shortcuts.addTaskNode, shortcut: "Ctrl+1" }, + { action: t.shortcuts.addTopicNode, shortcut: "Ctrl+2" }, + { action: t.shortcuts.addImageNode, shortcut: "Ctrl+3" }, + { action: t.shortcuts.addTextNode, shortcut: "Ctrl+4" }, + { action: t.shortcuts.deleteNodeEdge, shortcut: "Delete" }, + { action: t.shortcuts.togglePreviewMode, shortcut: "Ctrl+P" }, + { action: t.shortcuts.toggleDebugMode, shortcut: "Ctrl+D" }, + { action: t.shortcuts.selectMultipleNodes, shortcut: "Ctrl+Click or Shift+Drag" }, + { action: t.shortcuts.selectAllNodes, shortcut: "Ctrl+A" }, + { action: t.shortcuts.showHelp, shortcut: "Ctrl+? or Help Button" }, + { action: t.shortcuts.zoomIn, shortcut: "Ctrl++" }, + { action: t.shortcuts.zoomOut, shortcut: "Ctrl+-" }, + { action: t.shortcuts.resetZoom, shortcut: "Ctrl+0" }, + { action: t.shortcuts.fitView, shortcut: "Shift+1" }, + { action: t.shortcuts.zoomToSelection, shortcut: "Shift+2" }, + { action: t.shortcuts.toggleGrid, shortcut: "Ctrl+'" }, + { action: t.shortcuts.resetMap, shortcut: "Ctrl+Delete" }, + { action: t.shortcuts.cut, shortcut: "Ctrl+X" }, + { action: t.shortcuts.copy, shortcut: "Ctrl+C" }, + { action: t.shortcuts.paste, shortcut: "Ctrl+V" }, + ]; + + useEffect(() => { + loadRoadmapData(parsedRoadmap); + }, [roadmapData, loadRoadmapData]); + + useEffect(() => { + // Filter out existing debug edges, but use the store's edges directly to avoid dependency loop + const baseEdges = useEditorStore.getState().edges.filter((e) => !e.id.startsWith("debug-")); + const newEdges: Edge[] = [...baseEdges]; + + if (debugMode) { + nodes.forEach((node) => { + if (showCompletionNeeds && node.type === "topic" && node.data?.completion?.needs) { + node.data.completion.needs.forEach((needId: string) => { + const edgeId = `debug-edge-${needId}-to-${node.id}`; + newEdges.push({ + id: edgeId, + target: needId, + source: node.id, + animated: true, + style: { stroke: "#f97316", strokeWidth: 2, strokeDasharray: "5,5" }, + type: "floating", + }); + }); + } + if (showCompletionOptional && node.data?.completion?.optional) { + node.data.completion.optional.forEach((optionalId: string) => { + const edgeId = `debug-edge-optional-${optionalId}-to-${node.id}`; + newEdges.push({ + id: edgeId, + target: optionalId, + source: node.id, + animated: true, + style: { stroke: "#eab308", strokeWidth: 2, strokeDasharray: "5,5" }, + type: "floating", + }); + }); + } + }); + nodes.forEach((node) => { + if (showUnlockAfter && node.data.unlock?.after) { + node.data.unlock.after.forEach((unlockId: string) => { + const edgeId = `debug-edge-${unlockId}-to-${node.id}`; + newEdges.push({ + id: edgeId, + target: unlockId, + source: node.id, + animated: true, + style: { stroke: "#10b981", strokeWidth: 2, strokeDasharray: "5,5" }, + type: "floating", + }); + }); + } + }); + } + setEdges(newEdges); + }, [nodes, debugMode, showCompletionNeeds, showCompletionOptional, showUnlockAfter, setEdges]); + + // Event handlers + const handleNodeClick = useCallback((_: any, node: Node) => { + setSelectedNodeId(node.id); + setDrawerOpen(true); + }, [setSelectedNodeId, setDrawerOpen]); + + const handleEdgeClick = useCallback((_: any, edge: Edge) => { + setSelectedEdge(edge); + setEdgeDrawerOpen(true); + }, [setSelectedEdge, setEdgeDrawerOpen]); + + const closeDrawer = useCallback(() => { + closeAllDrawers(); + }, [closeAllDrawers]); + + const handleUpdateNode = useCallback( + (updatedNode: Node) => { + updateNode(updatedNode.id, updatedNode); + }, + [updateNode] + ); + + const handleUpdateNodes = useCallback( + (updatedNodes: Node[]) => { + updateNodes(updatedNodes); + }, + [updateNodes] + ); + + const handleUpdateEdge = useCallback( + (updatedEdge: Edge) => { + updateEdge(updatedEdge.id, updatedEdge); + }, + [updateEdge] + ); + + // Delete selected edge + const handleDeleteEdge = useCallback(() => { + if (!selectedEdge) return; + deleteEdge(selectedEdge.id); + closeAllDrawers(); + }, [selectedEdge, deleteEdge, closeAllDrawers]); + + const handleDeleteNode = useCallback(() => { + if (!selectedNodeId) return; + deleteNode(selectedNodeId); + closeAllDrawers(); + }, [selectedNodeId, deleteNode, closeAllDrawers]); + + const addNewNode = useCallback( + (type: "task" | "topic" | "image" | "text") => { + // Use last mouse position if available, otherwise use center of screen + const position = lastMousePosition + ? screenToFlowPosition(lastMousePosition) + : screenToFlowPosition({ x: window.innerWidth / 2, y: window.innerHeight / 2 }); + + if (type === "task") { + const newNode: Node = { + id: `node${nextNodeId}`, + type, + position, + data: { + label: t.newTask, + summary: "", + description: "", + }, + }; + addNode(newNode); + setNextNodeId(nextNodeId + 1); + } else if (type === "topic") { + const newNode: Node = { + id: `node${nextNodeId}`, + type, + position, + data: { + label: t.newTopic, + summary: "", + description: "", + }, + }; + addNode(newNode); + setNextNodeId(nextNodeId + 1); + } + else if (type === "image") { + const newNode: Node = { + id: `background-node${nextNodeId}`, + type, + zIndex: -2, + position, + data: { + src: "", + }, + }; + addNode(newNode); + setNextNodeId(nextNodeId + 1); + } else if (type === "text") { + const newNode: Node = { + id: `background-node${nextNodeId}`, + type, + position, + zIndex: -1, + data: { + text: t.backgroundTextDefault, + fontSize: 32, + color: "#e5e7eb", + }, + }; + addNode(newNode); + setNextNodeId(nextNodeId + 1); + } + }, + [nextNodeId, lastMousePosition, screenToFlowPosition, addNode, setNextNodeId, t] + ); + + const handleSave = useCallback(() => { + const roadmapData = getRoadmapData(); + setSaved(true); + + if (onChange) { + onChange(roadmapData); + return; + } else { + const root = document.querySelector("hyperbook-learningmap-editor"); + if (root) { + root.dispatchEvent(new CustomEvent("change", { detail: roadmapData })); + } + } + }, [nodes, edges, settings, onChange, getRoadmapData, setSaved]); + + // Auto-save when changes are made + useEffect(() => { + if (!saved) { + setTimeout(() => { + handleSave(); + }, 2000); + } + }, [saved, handleSave]); + + const togglePreviewMode = useCallback(() => { + handleSave(); + const newMode = !previewMode; + setPreviewMode(newMode); + if (newMode) { + setDebugMode(false); + closeDrawer(); + } + }, [previewMode, setPreviewMode, setDebugMode, handleSave, closeDrawer]); + + const toggleDebugMode = useCallback(() => { + setDebugMode(!debugMode); + }, [debugMode, setDebugMode]); + + const handleDownload = useCallback(() => { + const roadmapData = getRoadmapData(); + const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(roadmapData, null, 2)); + const downloadAnchorNode = document.createElement('a'); + downloadAnchorNode.setAttribute("href", dataStr); + downloadAnchorNode.setAttribute("download", `${roadmapData.settings.title?.trim() ?? getDefaultFilename()}.learningmap`); + document.body.appendChild(downloadAnchorNode); // required for firefox + downloadAnchorNode.click(); + downloadAnchorNode.remove(); + }, [getRoadmapData]); + + const handleShare = useCallback(() => { + const roadmapData = getRoadmapData(); + + // Check if map is empty (no nodes) + if (!roadmapData.nodes || roadmapData.nodes.length === 0) { + alert(t.emptyMapCannotBeShared); + return; + } + + // Upload to JSON store + fetch(`${jsonStore}/api/v2/post`, { + method: "POST", + mode: "cors", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(roadmapData), + }) + .then((r) => r.json()) + .then((json) => { + const link = window.location.origin + window.location.pathname + "#json=" + json.id; + setShareLink(link); + setShareDialogOpen(true); + }) + .catch(() => { + alert(t.uploadFailed); + }); + }, [getRoadmapData, jsonStore, t, setShareLink, setShareDialogOpen]); + + const loadFromJsonStore = useCallback((id: string) => { + fetch(`${jsonStore}/api/v2/${id}`, { + method: "GET", + mode: "cors", + }) + .then((r) => r.text()) + .then((text) => { + const json = JSON.parse(text); + loadRoadmapData(json); + setLoadExternalDialogOpen(false); + setPendingExternalId(null); + }) + .catch(() => { + alert(t.loadFailed); + }); + }, [jsonStore, t, loadRoadmapData, setLoadExternalDialogOpen, setPendingExternalId]); + + const handleLoadExternal = useCallback((id: string) => { + setPendingExternalId(id); + setLoadExternalDialogOpen(true); + }, [setPendingExternalId, setLoadExternalDialogOpen]); + + // Check for external JSON in URL hash on mount + useEffect(() => { + const hash = window.location.hash; + if (hash.startsWith("#json=")) { + const id = hash.substring(6); + handleLoadExternal(id); + } + }, [handleLoadExternal]); + + + const defaultEdgeOptions = { + animated: false, + style: { + stroke: "#94a3b8", + strokeWidth: 2, + }, + type: "default", + }; + + const handleOpen = useCallback(() => { + const input = document.createElement('input'); + input.type = 'file'; + input.accept = '.learningmap,application/json'; + input.onchange = (e: any) => { + const file = e.target.files[0]; + if (!file) return; + + if (!window.confirm(t.openFileWarning)) { + return; + } + + const reader = new FileReader(); + reader.onload = (evt) => { + try { + const content = evt.target?.result; + if (typeof content === 'string') { + const json = JSON.parse(content); + loadRoadmapData(json); + } + } catch (err) { + alert(t.failedToLoadFile); + } + }; + reader.readAsText(file); + }; + input.click(); + }, [loadRoadmapData, t]); + + // Toolbar handler wrappers for EditorToolbar props + const handleOpenSettingsDrawer = useCallback(() => setSettingsDrawerOpen(true), [setSettingsDrawerOpen]); + + const handleNodesChange: OnNodesChange = useCallback( + (changes) => { + onNodesChange(changes); + }, + [onNodesChange] + ); + + const handleEdgesChange: OnEdgesChange = useCallback( + (changes) => { + onEdgesChange(changes); + }, + [onEdgesChange] + ); + + const handleUndo = useCallback(() => { + if (canUndo) { + undo(); + } + }, [canUndo, undo]); + + const handleRedo = useCallback(() => { + if (canRedo) { + redo(); + } + }, [canRedo, redo]); + + const handleCut = useCallback(() => { + const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); + if (selectedNodes.length > 0) { + const selectedNodeIdSet = new Set(selectedNodeIds); + const relatedEdges = edges.filter(e => + selectedNodeIdSet.has(e.source) && selectedNodeIdSet.has(e.target) + ); + setClipboard({ nodes: selectedNodes, edges: relatedEdges }); + // Delete the selected nodes + selectedNodeIds.forEach(id => deleteNode(id)); + setSelectedNodeIds([]); + } + }, [nodes, edges, selectedNodeIds, deleteNode, setSelectedNodeIds, setClipboard]); + + const handleCopy = useCallback(() => { + const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); + if (selectedNodes.length > 0) { + const selectedNodeIdSet = new Set(selectedNodeIds); + const relatedEdges = edges.filter(e => + selectedNodeIdSet.has(e.source) && selectedNodeIdSet.has(e.target) + ); + setClipboard({ nodes: selectedNodes, edges: relatedEdges }); + } + }, [nodes, edges, selectedNodeIds, setClipboard]); + + const handlePaste = useCallback(() => { + if (!clipboard) return; + + // Create a mapping from old node IDs to new node IDs + const idMapping: Record = {}; + let newNextNodeId = nextNodeId; + + const newNodes = clipboard.nodes.map(node => { + const newId = node.id.startsWith('background-node') + ? `background-node${newNextNodeId}` + : `node${newNextNodeId}`; + idMapping[node.id] = newId; + newNextNodeId++; + + return { + ...node, + id: newId, + position: { + x: node.position.x + 50, + y: node.position.y + 50, + }, + }; + }); + + const newEdges = clipboard.edges.map((edge, idx) => ({ + ...edge, + id: `e${Date.now()}-${idx}`, + source: idMapping[edge.source] || edge.source, + target: idMapping[edge.target] || edge.target, + })); + + newNodes.forEach(node => addNode(node)); + setEdges([...edges, ...newEdges]); + setNextNodeId(newNextNodeId); + setSelectedNodeIds(newNodes.map(n => n.id)); + }, [clipboard, nextNodeId, edges, addNode, setEdges, setNextNodeId, setSelectedNodeIds]); + + const handleZoomIn = useCallback(() => { + zoomIn(); + }, [zoomIn]); + + const handleZoomOut = useCallback(() => { + zoomOut(); + }, [zoomOut]); + + const handleResetZoom = useCallback(() => { + setCenter(0, 0, { zoom: 1, duration: 300 }); + }, [setCenter]); + + const handleFitView = useCallback(() => { + fitView({ duration: 300 }); + }, [fitView]); + + const handleZoomToSelection = useCallback(() => { + if (selectedNodeIds.length > 0) { + fitView({ nodes: selectedNodeIds.map(s => ({ id: s })), duration: 300, padding: 0.2 }); + } + }, [selectedNodeIds, fitView]); + + const handleToggleGrid = useCallback(() => { + setShowGrid(!showGrid); + }, [showGrid, setShowGrid]); + + const handleResetMap = useCallback(() => { + if (confirm(t.resetMapWarning)) { + setNodes([]); + setEdges([]); + setNextNodeId(1); + } + }, [setNodes, setEdges, setNextNodeId, t]); + + const handleSelectAll = useCallback(() => { + setSelectedNodeIds(nodes.map(n => n.id)); + }, [nodes, setSelectedNodeIds]); + + const handleSelectionChange: OnSelectionChangeFunc = useCallback( + ({ nodes: selectedNodes }) => { + setSelectedNodeIds(selectedNodes.map(n => n.id)); + }, + [setSelectedNodeIds] + ); + + // Track mouse position for node placement + useEffect(() => { + const handleMouseMove = (e: MouseEvent) => { + setLastMousePosition({ x: e.clientX, y: e.clientY }); + }; + window.addEventListener("mousemove", handleMouseMove); + return () => { + window.removeEventListener("mousemove", handleMouseMove); + }; + }, []); + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + //save shortcut + if ((e.ctrlKey || e.metaKey) && e.key === 's' && !e.shiftKey) { + e.preventDefault(); + handleSave(); + } + // undo shortcut + if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) { + e.preventDefault(); + handleUndo(); + } + // redo shortcut + if ((e.ctrlKey || e.metaKey) && (e.key === 'y' || (e.shiftKey && e.key === 'Z'))) { + e.preventDefault(); + handleRedo(); + } + // add task node shortcut + if ((e.ctrlKey || e.metaKey) && e.key === '1' && !e.shiftKey) { + e.preventDefault(); + addNewNode("task"); + } + // add topic node shortcut + if ((e.ctrlKey || e.metaKey) && e.key === '2' && !e.shiftKey) { + e.preventDefault(); + addNewNode("topic"); + } + // add image node shortcut + if ((e.ctrlKey || e.metaKey) && e.key === '3' && !e.shiftKey) { + e.preventDefault(); + addNewNode("image"); + } + if ((e.ctrlKey || e.metaKey) && e.key === '4' && !e.shiftKey) { + e.preventDefault(); + addNewNode("text"); + } + + if ((e.ctrlKey || e.metaKey) && (e.key === '?' || (e.shiftKey && e.key === '/'))) { + e.preventDefault(); + setHelpOpen(!helpOpen); + } + //preview toggle shortcut + if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'p' && !e.shiftKey) { + e.preventDefault(); + togglePreviewMode(); + } + //debug toggle shortcut + if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'd' && !e.shiftKey) { + e.preventDefault(); + toggleDebugMode(); + } + + // Zoom in shortcut + if ((e.ctrlKey || e.metaKey) && (e.key === '+' || e.key === '=') && !e.shiftKey) { + e.preventDefault(); + handleZoomIn(); + } + // Zoom out shortcut + if ((e.ctrlKey || e.metaKey) && (e.key === '-' || e.key === '_') && !e.shiftKey) { + e.preventDefault(); + handleZoomOut(); + } + // Reset zoom shortcut + if ((e.ctrlKey || e.metaKey) && e.key === '0' && !e.shiftKey) { + e.preventDefault(); + handleResetZoom(); + } + // Fit view shortcut + if (e.shiftKey && e.code === 'Digit1' && !e.ctrlKey && !e.metaKey) { + e.preventDefault(); + handleFitView(); + } + // Zoom to selection shortcut + if (e.shiftKey && e.code === 'Digit2' && !e.ctrlKey && !e.metaKey) { + e.preventDefault(); + handleZoomToSelection(); + } + + // Toggle grid shortcut + if ((e.ctrlKey || e.metaKey) && e.code === "Backslash") { + e.preventDefault(); + handleToggleGrid(); + } + // Reset map shortcut + if ((e.ctrlKey || e.metaKey) && e.key === 'Delete') { + e.preventDefault(); + handleResetMap(); + } + // Cut shortcut + if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'x' && !e.shiftKey) { + e.preventDefault(); + handleCut(); + } + // Copy shortcut + if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'c' && !e.shiftKey) { + e.preventDefault(); + handleCopy(); + } + // Paste shortcut + if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'v' && !e.shiftKey) { + e.preventDefault(); + handlePaste(); + } + // Select all shortcut + if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'a' && !e.shiftKey) { + e.preventDefault(); + handleSelectAll(); + } + + // Dismiss with Escape + if (helpOpen && e.key === 'Escape') { + setHelpOpen(false); + } + }; + window.addEventListener("keydown", handleKeyDown); + return () => { + window.removeEventListener("keydown", handleKeyDown); + }; + }, [handleSave, handleUndo, handleRedo, addNewNode, helpOpen, setHelpOpen, togglePreviewMode, toggleDebugMode, + handleZoomIn, handleZoomOut, handleResetZoom, handleFitView, handleZoomToSelection, handleToggleGrid, + handleResetMap, handleCut, handleCopy, handlePaste, handleSelectAll]); + + return ( + <> + + {previewMode && } + {!previewMode && <> +
+ {nodes.length === 0 && edges.length === 0 && addNewNode("topic")} + onShowHelp={() => setHelpOpen(true)} + language={effectiveLanguage} + />} + + {showGrid && } + + + + + + + + + + + setHelpOpen(true)}> + + + + {!saved && { handleSave(); }}> + + } + {selectedNodeIds.length > 1 && } + +
+ + + + setHelpOpen(false)} + > +
+

{t.keyboardShortcuts}

+ +
+
+ + + + + + + + + {keyboardShortcuts.map((item) => ( + + + + + ))} + +
{t.action}{t.shortcut}
{item.action}{item.shortcut}
+
+
+ +
+
+ setShareDialogOpen(false)} + language={effectiveLanguage} + /> + { + setLoadExternalDialogOpen(false); + setPendingExternalId(null); + }} + onDownloadCurrent={handleDownload} + onReplace={() => { + if (pendingExternalId) { + loadFromJsonStore(pendingExternalId); + } + }} + language={effectiveLanguage} + /> + + } + + ); +} + +export default (props: LearningMapEditorProps) => { + return ( +
+ + + +
+ ) +} diff --git a/packages/learningmap/src/editorStore.ts b/packages/learningmap/src/editorStore.ts index aae30ac..14985e7 100644 --- a/packages/learningmap/src/editorStore.ts +++ b/packages/learningmap/src/editorStore.ts @@ -1,17 +1,7 @@ -import { create } from "zustand"; -import { temporal } from "zundo"; -import { persist } from "zustand/middleware"; -import { - Node, - Edge, - applyNodeChanges, - applyEdgeChanges, - addEdge, - NodeChange, - EdgeChange, - Connection, -} from "@xyflow/react"; -import { NodeData, RoadmapData, Settings } from "./types"; +import { create } from 'zustand'; +import { temporal } from 'zundo'; +import { Node, Edge, applyNodeChanges, applyEdgeChanges, addEdge, NodeChange, EdgeChange, Connection } from '@xyflow/react'; +import { NodeData, RoadmapData, Settings, ImageNodeData, TextNodeData } from './types'; // Note: This is a global store for the editor. Typically only one editor instance is active at a time. // If you need multiple independent editor instances, consider creating store instances per component or using context. @@ -20,8 +10,9 @@ export interface EditorState { nodes: Node[]; edges: Edge[]; settings: Settings; - + // UI state + saved: boolean; previewMode: boolean; debugMode: boolean; showGrid: boolean; @@ -31,24 +22,24 @@ export interface EditorState { edgeDrawerOpen: boolean; shareDialogOpen: boolean; loadExternalDialogOpen: boolean; - + // Selected items selectedNodeId: string | null; selectedNodeIds: string[]; selectedEdge: Edge | null; - + // Other state nextNodeId: number; clipboard: { nodes: Node[]; edges: Edge[] } | null; lastMousePosition: { x: number; y: number } | null; shareLink: string; pendingExternalId: string | null; - + // Debug settings showCompletionNeeds: boolean; showCompletionOptional: boolean; showUnlockAfter: boolean; - + // Actions onNodesChange: (changes: NodeChange>[]) => void; onEdgesChange: (changes: EdgeChange[]) => void; @@ -63,8 +54,9 @@ export interface EditorState { deleteNode: (nodeId: string) => void; deleteEdge: (edgeId: string) => void; addNode: (node: Node) => void; - + // UI state setters + setSaved: (saved: boolean) => void; setPreviewMode: (previewMode: boolean) => void; setDebugMode: (debugMode: boolean) => void; setShowGrid: (showGrid: boolean) => void; @@ -78,16 +70,14 @@ export interface EditorState { setSelectedNodeIds: (nodeIds: string[]) => void; setSelectedEdge: (edge: Edge | null) => void; setNextNodeId: (nextNodeId: number) => void; - setClipboard: ( - clipboard: { nodes: Node[]; edges: Edge[] } | null, - ) => void; + setClipboard: (clipboard: { nodes: Node[]; edges: Edge[] } | null) => void; setLastMousePosition: (position: { x: number; y: number } | null) => void; setShareLink: (shareLink: string) => void; setPendingExternalId: (pendingExternalId: string | null) => void; setShowCompletionNeeds: (showCompletionNeeds: boolean) => void; setShowCompletionOptional: (showCompletionOptional: boolean) => void; setShowUnlockAfter: (showUnlockAfter: boolean) => void; - + // Bulk operations loadRoadmapData: (roadmapData: RoadmapData) => void; getRoadmapData: () => RoadmapData; @@ -99,6 +89,7 @@ const initialState = { nodes: [], edges: [], settings: { background: { color: "#ffffff" } }, + saved: true, previewMode: false, debugMode: false, showGrid: false, @@ -123,241 +114,222 @@ const initialState = { export const useEditorStore = create()( temporal( - persist( - (set, get) => ({ - ...initialState, - - // ReactFlow handlers - onNodesChange: (changes) => { - set({ - nodes: applyNodeChanges(changes, get().nodes), - }); - }, - - onEdgesChange: (changes) => { - set({ - edges: applyEdgeChanges(changes, get().edges), - }); - }, - - onConnect: (connection) => { - set({ - edges: addEdge(connection, get().edges), - }); - }, - - // Node operations - setNodes: (nodes) => { - set({ nodes }); - }, - - setEdges: (edges) => { - set({ edges }); - }, + (set, get) => ({ + ...initialState, + + // ReactFlow handlers + onNodesChange: (changes) => { + set({ + nodes: applyNodeChanges(changes, get().nodes), + saved: false, + }); + }, - setSettings: (settings) => { - set({ settings }); - }, + onEdgesChange: (changes) => { + set({ + edges: applyEdgeChanges(changes, get().edges), + saved: false, + }); + }, - updateNode: (nodeId, updates) => { - set({ - nodes: get().nodes.map((n) => - n.id === nodeId ? { ...n, ...updates } : n, - ), - }); - }, + onConnect: (connection) => { + set({ + edges: addEdge(connection, get().edges), + saved: false, + }); + }, - updateNodeData: (nodeId, dataUpdates) => { - set({ - nodes: get().nodes.map((n) => - n.id === nodeId - ? { ...n, data: { ...n.data, ...dataUpdates } } - : n, - ), - }); - }, + // Node operations + setNodes: (nodes) => { + set({ nodes, saved: false }); + }, - updateNodes: (updates) => { - set({ - nodes: get().nodes.map((n) => { - const updated = updates.find((un) => un.id === n.id); - return updated ? updated : n; - }), - }); - }, + setEdges: (edges) => { + set({ edges, saved: false }); + }, - updateEdge: (edgeId, updates) => { - set({ - edges: get().edges.map((e) => - e.id === edgeId ? { ...e, ...updates } : e, - ), - }); - // Update selected edge if it's the one being updated - const selectedEdge = get().selectedEdge; - if (selectedEdge && selectedEdge.id === edgeId) { - set({ selectedEdge: { ...selectedEdge, ...updates } }); - } - }, + setSettings: (settings) => { + set({ settings, saved: false }); + }, - deleteNode: (nodeId) => { - set({ - nodes: get().nodes.filter((n) => n.id !== nodeId), - edges: get().edges.filter( - (e) => e.source !== nodeId && e.target !== nodeId, - ), - }); - }, + updateNode: (nodeId, updates) => { + set({ + nodes: get().nodes.map((n) => + n.id === nodeId ? { ...n, ...updates } : n + ), + saved: false, + }); + }, - deleteEdge: (edgeId) => { - set({ - edges: get().edges.filter((e) => e.id !== edgeId), - }); - }, + updateNodeData: (nodeId, dataUpdates) => { + set({ + nodes: get().nodes.map((n) => + n.id === nodeId ? { ...n, data: { ...n.data, ...dataUpdates } } : n + ), + saved: false, + }); + }, - addNode: (node) => { - set({ - nodes: [...get().nodes, node], - }); - }, + updateNodes: (updates) => { + set({ + nodes: get().nodes.map((n) => { + const updated = updates.find((un) => un.id === n.id); + return updated ? updated : n; + }), + saved: false, + }); + }, - // UI state setters - setPreviewMode: (previewMode) => set({ previewMode }), - setDebugMode: (debugMode) => set({ debugMode }), - setShowGrid: (showGrid) => set({ showGrid }), - setHelpOpen: (helpOpen) => set({ helpOpen }), - setDrawerOpen: (drawerOpen) => set({ drawerOpen }), - setSettingsDrawerOpen: (settingsDrawerOpen) => - set({ settingsDrawerOpen }), - setEdgeDrawerOpen: (edgeDrawerOpen) => set({ edgeDrawerOpen }), - setShareDialogOpen: (shareDialogOpen) => set({ shareDialogOpen }), - setLoadExternalDialogOpen: (loadExternalDialogOpen) => - set({ loadExternalDialogOpen }), - setSelectedNodeId: (selectedNodeId) => set({ selectedNodeId }), - setSelectedNodeIds: (selectedNodeIds) => set({ selectedNodeIds }), - setSelectedEdge: (selectedEdge) => set({ selectedEdge }), - setNextNodeId: (nextNodeId) => set({ nextNodeId }), - setClipboard: (clipboard) => set({ clipboard }), - setLastMousePosition: (lastMousePosition) => set({ lastMousePosition }), - setShareLink: (shareLink) => set({ shareLink }), - setPendingExternalId: (pendingExternalId) => set({ pendingExternalId }), - setShowCompletionNeeds: (showCompletionNeeds) => - set({ showCompletionNeeds }), - setShowCompletionOptional: (showCompletionOptional) => - set({ showCompletionOptional }), - setShowUnlockAfter: (showUnlockAfter) => set({ showUnlockAfter }), + updateEdge: (edgeId, updates) => { + set({ + edges: get().edges.map((e) => + e.id === edgeId ? { ...e, ...updates } : e + ), + saved: false, + }); + // Update selected edge if it's the one being updated + const selectedEdge = get().selectedEdge; + if (selectedEdge && selectedEdge.id === edgeId) { + set({ selectedEdge: { ...selectedEdge, ...updates } }); + } + }, - // Bulk operations - loadRoadmapData: (roadmapData) => { - const nodesArr = Array.isArray(roadmapData?.nodes) - ? roadmapData.nodes - : []; - const edgesArr = Array.isArray(roadmapData?.edges) - ? roadmapData.edges - : []; + deleteNode: (nodeId) => { + set({ + nodes: get().nodes.filter((n) => n.id !== nodeId), + edges: get().edges.filter((e) => e.source !== nodeId && e.target !== nodeId), + saved: false, + }); + }, - const rawNodes = nodesArr.map((n) => ({ - ...n, - draggable: true, - className: n.data.color ? n.data.color : n.className, - data: { ...n.data }, - })); + deleteEdge: (edgeId) => { + set({ + edges: get().edges.filter((e) => e.id !== edgeId), + saved: false, + }); + }, - // Calculate next node ID - let nextNodeId = 1; - if (nodesArr.length > 0) { - const maxId = Math.max( - ...nodesArr - .map((n) => parseInt(n.id.replace(/\D/g, ""), 10)) - .filter((id) => !isNaN(id)), - ); - nextNodeId = maxId + 1; - } + addNode: (node) => { + set({ + nodes: [...get().nodes, node], + saved: false, + }); + }, - set({ - nodes: rawNodes, - edges: edgesArr, - settings: roadmapData?.settings || { - background: { color: "#ffffff" }, - }, - nextNodeId, - }); - }, + // UI state setters + setSaved: (saved) => set({ saved }), + setPreviewMode: (previewMode) => set({ previewMode }), + setDebugMode: (debugMode) => set({ debugMode }), + setShowGrid: (showGrid) => set({ showGrid }), + setHelpOpen: (helpOpen) => set({ helpOpen }), + setDrawerOpen: (drawerOpen) => set({ drawerOpen }), + setSettingsDrawerOpen: (settingsDrawerOpen) => set({ settingsDrawerOpen }), + setEdgeDrawerOpen: (edgeDrawerOpen) => set({ edgeDrawerOpen }), + setShareDialogOpen: (shareDialogOpen) => set({ shareDialogOpen }), + setLoadExternalDialogOpen: (loadExternalDialogOpen) => set({ loadExternalDialogOpen }), + setSelectedNodeId: (selectedNodeId) => set({ selectedNodeId }), + setSelectedNodeIds: (selectedNodeIds) => set({ selectedNodeIds }), + setSelectedEdge: (selectedEdge) => set({ selectedEdge }), + setNextNodeId: (nextNodeId) => set({ nextNodeId }), + setClipboard: (clipboard) => set({ clipboard }), + setLastMousePosition: (lastMousePosition) => set({ lastMousePosition }), + setShareLink: (shareLink) => set({ shareLink }), + setPendingExternalId: (pendingExternalId) => set({ pendingExternalId }), + setShowCompletionNeeds: (showCompletionNeeds) => set({ showCompletionNeeds }), + setShowCompletionOptional: (showCompletionOptional) => set({ showCompletionOptional }), + setShowUnlockAfter: (showUnlockAfter) => set({ showUnlockAfter }), + + // Bulk operations + loadRoadmapData: (roadmapData) => { + const nodesArr = Array.isArray(roadmapData?.nodes) ? roadmapData.nodes : []; + const edgesArr = Array.isArray(roadmapData?.edges) ? roadmapData.edges : []; + + const rawNodes = nodesArr.map((n) => ({ + ...n, + draggable: true, + className: n.data.color ? n.data.color : n.className, + data: { ...n.data }, + })); + + // Calculate next node ID + let nextNodeId = 1; + if (nodesArr.length > 0) { + const maxId = Math.max( + ...nodesArr + .map((n) => parseInt(n.id.replace(/\D/g, ""), 10)) + .filter((id) => !isNaN(id)) + ); + nextNodeId = maxId + 1; + } + + set({ + nodes: rawNodes, + edges: edgesArr, + settings: roadmapData?.settings || { background: { color: "#ffffff" } }, + nextNodeId, + }); + }, - getRoadmapData: () => { - const state = get(); - return { - nodes: state.nodes.map((n) => ({ - id: n.id, - type: n.type, - position: n.position, - width: n.width, - height: n.height, - zIndex: n.zIndex, - data: n.data, + getRoadmapData: () => { + const state = get(); + return { + nodes: state.nodes.map((n) => ({ + id: n.id, + type: n.type, + position: n.position, + width: n.width, + height: n.height, + zIndex: n.zIndex, + data: n.data, + })), + edges: state.edges + .filter((e) => !e.id.startsWith("debug-")) + .map((e) => ({ + id: e.id, + source: e.source, + target: e.target, + sourceHandle: e.sourceHandle, + targetHandle: e.targetHandle, + animated: e.animated, + type: e.type, + style: e.style, })), - edges: state.edges - .filter((e) => !e.id.startsWith("debug-")) - .map((e) => ({ - id: e.id, - source: e.source, - target: e.target, - sourceHandle: e.sourceHandle, - targetHandle: e.targetHandle, - animated: e.animated, - type: e.type, - style: e.style, - })), - settings: state.settings, - version: 1, - }; - }, + settings: state.settings, + version: 1, + }; + }, - closeAllDrawers: () => { - set({ - drawerOpen: false, - selectedNodeId: null, - edgeDrawerOpen: false, - selectedEdge: null, - settingsDrawerOpen: false, - }); - }, + closeAllDrawers: () => { + set({ + drawerOpen: false, + selectedNodeId: null, + edgeDrawerOpen: false, + selectedEdge: null, + settingsDrawerOpen: false, + }); + }, - reset: () => { - set(initialState); - }, - }), - { - name: "roadmap-data", - partialize: (state) => ({ - nodes: state.nodes, - edges: state.edges, - settings: state.settings, - }), + reset: () => { + set(initialState); }, - ), + }), { // Zundo options limit: 100, equality: (a, b) => a === b, - }, - ), + } + ) ); // Hook for accessing temporal store (undo/redo) -import { useStore } from "zustand"; +import { useStore } from 'zustand'; export const useTemporalStore = () => { const undo = useEditorStore.temporal.getState().undo; const redo = useEditorStore.temporal.getState().redo; - const pastStates = useStore( - useEditorStore.temporal, - (state) => state.pastStates, - ); - const futureStates = useStore( - useEditorStore.temporal, - (state) => state.futureStates, - ); - + const pastStates = useStore(useEditorStore.temporal, (state) => state.pastStates); + const futureStates = useStore(useEditorStore.temporal, (state) => state.futureStates); + return { undo, redo, diff --git a/packages/learningmap/src/useEditorActions.ts b/packages/learningmap/src/useEditorActions.ts new file mode 100644 index 0000000..054ed18 --- /dev/null +++ b/packages/learningmap/src/useEditorActions.ts @@ -0,0 +1,415 @@ +import { useCallback } from "react"; +import { useReactFlow } from "@xyflow/react"; +import { Node, Edge } from "@xyflow/react"; +import { useEditorStore } from "./editorStore"; +import { NodeData, ImageNodeData, TextNodeData } from "./types"; + +export const useEditorActions = (t: any, screenToFlowPosition: any, jsonStore: string) => { + const { zoomIn, zoomOut, setCenter, fitView } = useReactFlow(); + + // Get store state + const nodes = useEditorStore(state => state.nodes); + const edges = useEditorStore(state => state.edges); + const selectedNodeId = useEditorStore(state => state.selectedNodeId); + const selectedNodeIds = useEditorStore(state => state.selectedNodeIds); + const selectedEdge = useEditorStore(state => state.selectedEdge); + const clipboard = useEditorStore(state => state.clipboard); + const nextNodeId = useEditorStore(state => state.nextNodeId); + const lastMousePosition = useEditorStore(state => state.lastMousePosition); + const debugMode = useEditorStore(state => state.debugMode); + const previewMode = useEditorStore(state => state.previewMode); + const showGrid = useEditorStore(state => state.showGrid); + + // Get store actions + const setSelectedNodeId = useEditorStore(state => state.setSelectedNodeId); + const setDrawerOpen = useEditorStore(state => state.setDrawerOpen); + const setSelectedEdge = useEditorStore(state => state.setSelectedEdge); + const setEdgeDrawerOpen = useEditorStore(state => state.setEdgeDrawerOpen); + const updateNode = useEditorStore(state => state.updateNode); + const updateNodes = useEditorStore(state => state.updateNodes); + const updateEdge = useEditorStore(state => state.updateEdge); + const deleteNode = useEditorStore(state => state.deleteNode); + const deleteEdge = useEditorStore(state => state.deleteEdge); + const addNode = useEditorStore(state => state.addNode); + const setNextNodeId = useEditorStore(state => state.setNextNodeId); + const setClipboard = useEditorStore(state => state.setClipboard); + const setSelectedNodeIds = useEditorStore(state => state.setSelectedNodeIds); + const setNodes = useEditorStore(state => state.setNodes); + const setEdges = useEditorStore(state => state.setEdges); + const getRoadmapData = useEditorStore(state => state.getRoadmapData); + const loadRoadmapData = useEditorStore(state => state.loadRoadmapData); + const setShareDialogOpen = useEditorStore(state => state.setShareDialogOpen); + const setShareLink = useEditorStore(state => state.setShareLink); + const setLoadExternalDialogOpen = useEditorStore(state => state.setLoadExternalDialogOpen); + const setPendingExternalId = useEditorStore(state => state.setPendingExternalId); + const closeAllDrawers = useEditorStore(state => state.closeAllDrawers); + const setShowGrid = useEditorStore(state => state.setShowGrid); + const setDebugMode = useEditorStore(state => state.setDebugMode); + const setPreviewMode = useEditorStore(state => state.setPreviewMode); + const setSettingsDrawerOpen = useEditorStore(state => state.setSettingsDrawerOpen); + + const handleNodeClick = useCallback((_: any, node: Node) => { + setSelectedNodeId(node.id); + setDrawerOpen(true); + }, [setSelectedNodeId, setDrawerOpen]); + + const handleEdgeClick = useCallback((_: any, edge: Edge) => { + setSelectedEdge(edge); + setEdgeDrawerOpen(true); + }, [setSelectedEdge, setEdgeDrawerOpen]); + + const closeDrawer = useCallback(() => { + closeAllDrawers(); + }, [closeAllDrawers]); + + const handleUpdateNode = useCallback( + (updatedNode: Node) => { + updateNode(updatedNode.id, updatedNode); + }, + [updateNode] + ); + + const handleUpdateNodes = useCallback( + (updatedNodes: Node[]) => { + updateNodes(updatedNodes); + }, + [updateNodes] + ); + + const handleUpdateEdge = useCallback( + (updatedEdge: Edge) => { + updateEdge(updatedEdge.id, updatedEdge); + }, + [updateEdge] + ); + + const handleDeleteEdge = useCallback(() => { + if (!selectedEdge) return; + deleteEdge(selectedEdge.id); + closeAllDrawers(); + }, [selectedEdge, deleteEdge, closeAllDrawers]); + + const handleDeleteNode = useCallback(() => { + if (!selectedNodeId) return; + deleteNode(selectedNodeId); + closeAllDrawers(); + }, [selectedNodeId, deleteNode, closeAllDrawers]); + + const addNewNode = useCallback( + (type: "task" | "topic" | "image" | "text") => { + const position = lastMousePosition + ? screenToFlowPosition(lastMousePosition) + : screenToFlowPosition({ x: window.innerWidth / 2, y: window.innerHeight / 2 }); + + if (type === "task") { + const newNode: Node = { + id: `node${nextNodeId}`, + type, + position, + data: { + label: t.newTask, + summary: "", + description: "", + }, + }; + addNode(newNode); + setNextNodeId(nextNodeId + 1); + } else if (type === "topic") { + const newNode: Node = { + id: `node${nextNodeId}`, + type, + position, + data: { + label: t.newTopic, + summary: "", + description: "", + }, + }; + addNode(newNode); + setNextNodeId(nextNodeId + 1); + } + else if (type === "image") { + const newNode: Node = { + id: `background-node${nextNodeId}`, + type, + zIndex: -2, + position, + data: { + src: "", + }, + }; + addNode(newNode); + setNextNodeId(nextNodeId + 1); + } else if (type === "text") { + const newNode: Node = { + id: `background-node${nextNodeId}`, + type, + position, + zIndex: -1, + data: { + text: t.backgroundTextDefault, + fontSize: 32, + color: "#e5e7eb", + }, + }; + addNode(newNode); + setNextNodeId(nextNodeId + 1); + } + }, + [nextNodeId, lastMousePosition, screenToFlowPosition, addNode, setNextNodeId, t] + ); + + const handleSave = useCallback(() => { + const roadmapData = getRoadmapData(); + return roadmapData; + }, [getRoadmapData]); + + const togglePreviewMode = useCallback(() => { + const newMode = !previewMode; + setPreviewMode(newMode); + if (newMode) { + setDebugMode(false); + closeDrawer(); + } + }, [previewMode, setPreviewMode, setDebugMode, closeDrawer]); + + const toggleDebugMode = useCallback(() => { + setDebugMode(!debugMode); + }, [debugMode, setDebugMode]); + + const handleDownload = useCallback(() => { + const roadmapData = getRoadmapData(); + const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(roadmapData, null, 2)); + const downloadAnchorNode = document.createElement('a'); + downloadAnchorNode.setAttribute("href", dataStr); + downloadAnchorNode.setAttribute("download", `${roadmapData.settings.title?.trim() ?? getDefaultFilename()}.learningmap`); + document.body.appendChild(downloadAnchorNode); + downloadAnchorNode.click(); + downloadAnchorNode.remove(); + }, [getRoadmapData]); + + const handleShare = useCallback(() => { + const roadmapData = getRoadmapData(); + + if (!roadmapData.nodes || roadmapData.nodes.length === 0) { + alert(t.emptyMapCannotBeShared); + return; + } + + fetch(`${jsonStore}/api/v2/post`, { + method: "POST", + mode: "cors", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(roadmapData), + }) + .then((r) => r.json()) + .then((json) => { + const link = window.location.origin + window.location.pathname + "#json=" + json.id; + setShareLink(link); + setShareDialogOpen(true); + }) + .catch(() => { + alert(t.uploadFailed); + }); + }, [getRoadmapData, jsonStore, t, setShareLink, setShareDialogOpen]); + + const loadFromJsonStore = useCallback((id: string) => { + fetch(`${jsonStore}/api/v2/${id}`, { + method: "GET", + mode: "cors", + }) + .then((r) => r.text()) + .then((text) => { + const json = JSON.parse(text); + loadRoadmapData(json); + setLoadExternalDialogOpen(false); + setPendingExternalId(null); + }) + .catch(() => { + alert(t.loadFailed); + }); + }, [jsonStore, t, loadRoadmapData, setLoadExternalDialogOpen, setPendingExternalId]); + + const handleLoadExternal = useCallback((id: string) => { + setPendingExternalId(id); + setLoadExternalDialogOpen(true); + }, [setPendingExternalId, setLoadExternalDialogOpen]); + + const handleOpen = useCallback(() => { + const input = document.createElement('input'); + input.type = 'file'; + input.accept = '.learningmap,application/json'; + input.onchange = (e: any) => { + const file = e.target.files[0]; + if (!file) return; + + if (!window.confirm(t.openFileWarning)) { + return; + } + + const reader = new FileReader(); + reader.onload = (evt) => { + try { + const content = evt.target?.result; + if (typeof content === 'string') { + const json = JSON.parse(content); + loadRoadmapData(json); + } + } catch (err) { + alert(t.failedToLoadFile); + } + }; + reader.readAsText(file); + }; + input.click(); + }, [loadRoadmapData, t]); + + const handleOpenSettingsDrawer = useCallback(() => setSettingsDrawerOpen(true), [setSettingsDrawerOpen]); + + const handleCut = useCallback(() => { + const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); + if (selectedNodes.length > 0) { + const selectedNodeIdSet = new Set(selectedNodeIds); + const relatedEdges = edges.filter(e => + selectedNodeIdSet.has(e.source) && selectedNodeIdSet.has(e.target) + ); + setClipboard({ nodes: selectedNodes, edges: relatedEdges }); + selectedNodeIds.forEach(id => deleteNode(id)); + setSelectedNodeIds([]); + } + }, [nodes, edges, selectedNodeIds, deleteNode, setSelectedNodeIds, setClipboard]); + + const handleCopy = useCallback(() => { + const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); + if (selectedNodes.length > 0) { + const selectedNodeIdSet = new Set(selectedNodeIds); + const relatedEdges = edges.filter(e => + selectedNodeIdSet.has(e.source) && selectedNodeIdSet.has(e.target) + ); + setClipboard({ nodes: selectedNodes, edges: relatedEdges }); + } + }, [nodes, edges, selectedNodeIds, setClipboard]); + + const handlePaste = useCallback(() => { + if (!clipboard) return; + + const idMapping: Record = {}; + let newNextNodeId = nextNodeId; + + const newNodes = clipboard.nodes.map(node => { + const newId = node.id.startsWith('background-node') + ? `background-node${newNextNodeId}` + : `node${newNextNodeId}`; + idMapping[node.id] = newId; + newNextNodeId++; + + return { + ...node, + id: newId, + position: { + x: node.position.x + 50, + y: node.position.y + 50, + }, + }; + }); + + const newEdges = clipboard.edges.map((edge, idx) => ({ + ...edge, + id: `e${Date.now()}-${idx}`, + source: idMapping[edge.source] || edge.source, + target: idMapping[edge.target] || edge.target, + })); + + newNodes.forEach(node => addNode(node)); + setEdges([...edges, ...newEdges]); + setNextNodeId(newNextNodeId); + setSelectedNodeIds(newNodes.map(n => n.id)); + }, [clipboard, nextNodeId, edges, addNode, setEdges, setNextNodeId, setSelectedNodeIds]); + + const handleZoomIn = useCallback(() => { + zoomIn(); + }, [zoomIn]); + + const handleZoomOut = useCallback(() => { + zoomOut(); + }, [zoomOut]); + + const handleResetZoom = useCallback(() => { + setCenter(0, 0, { zoom: 1, duration: 300 }); + }, [setCenter]); + + const handleFitView = useCallback(() => { + fitView({ duration: 300 }); + }, [fitView]); + + const handleZoomToSelection = useCallback(() => { + if (selectedNodeIds.length > 0) { + fitView({ nodes: selectedNodeIds.map(s => ({ id: s })), duration: 300, padding: 0.2 }); + } + }, [selectedNodeIds, fitView]); + + const handleToggleGrid = useCallback(() => { + setShowGrid(!showGrid); + }, [showGrid, setShowGrid]); + + const handleResetMap = useCallback(() => { + if (confirm(t.resetMapWarning)) { + setNodes([]); + setEdges([]); + setNextNodeId(1); + } + }, [setNodes, setEdges, setNextNodeId, t]); + + const handleSelectAll = useCallback(() => { + setSelectedNodeIds(nodes.map(n => n.id)); + }, [nodes, setSelectedNodeIds]); + + const handleDeleteSelected = useCallback(() => { + if (selectedEdge) { + handleDeleteEdge(); + } else if (selectedNodeId) { + handleDeleteNode(); + } + }, [selectedEdge, selectedNodeId, handleDeleteEdge, handleDeleteNode]); + + return { + handleNodeClick, + handleEdgeClick, + closeDrawer, + handleUpdateNode, + handleUpdateNodes, + handleUpdateEdge, + handleDeleteEdge, + handleDeleteNode, + addNewNode, + handleSave, + togglePreviewMode, + toggleDebugMode, + handleDownload, + handleShare, + loadFromJsonStore, + handleLoadExternal, + handleOpen, + handleOpenSettingsDrawer, + handleCut, + handleCopy, + handlePaste, + handleZoomIn, + handleZoomOut, + handleResetZoom, + handleFitView, + handleZoomToSelection, + handleToggleGrid, + handleResetMap, + handleSelectAll, + handleDeleteSelected, + }; +}; + +const getDefaultFilename = () => { + const now = new Date(); + const pad = (n: number) => n.toString().padStart(2, '0'); + return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}`; +}; From f4d60a72521f0523def5dc8bb84544ee1ec7fe05 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 11:43:36 +0000 Subject: [PATCH 12/17] Remove accidentally committed backup file Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- .../src/LearningMapEditor.tsx.backup | 899 ------------------ 1 file changed, 899 deletions(-) delete mode 100644 packages/learningmap/src/LearningMapEditor.tsx.backup diff --git a/packages/learningmap/src/LearningMapEditor.tsx.backup b/packages/learningmap/src/LearningMapEditor.tsx.backup deleted file mode 100644 index 773b8d9..0000000 --- a/packages/learningmap/src/LearningMapEditor.tsx.backup +++ /dev/null @@ -1,899 +0,0 @@ -import { useCallback, useEffect } from "react"; -import { - ReactFlow, - Controls, - ColorMode, - useReactFlow, - Node, - Connection, - Edge, - Background, - ControlButton, - OnNodesChange, - OnEdgesChange, - Panel, - OnSelectionChangeFunc, - ReactFlowProvider, -} from "@xyflow/react"; -import { EditorDrawer } from "./EditorDrawer"; -import { EdgeDrawer } from "./EdgeDrawer"; -import { TaskNode } from "./nodes/TaskNode"; -import { TopicNode } from "./nodes/TopicNode"; -import { ImageNode } from "./nodes/ImageNode"; -import { TextNode } from "./nodes/TextNode"; -import { RoadmapData, NodeData, ImageNodeData, TextNodeData, Settings } from "./types"; -import { SettingsDrawer } from "./SettingsDrawer"; -import FloatingEdge from "./FloatingEdge"; -import { EditorToolbar } from "./EditorToolbar"; -import { parseRoadmapData } from "./helper"; -import { LearningMap } from "./LearningMap"; -import { Info, Redo, Undo, RotateCw, ShieldAlert, X } from "lucide-react"; -import { useEditorStore, useTemporalStore } from "./editorStore"; -import { MultiNodePanel } from "./MultiNodePanel"; -import { getTranslations } from "./translations"; -import { WelcomeMessage } from "./WelcomeMessage"; -import { ShareDialog } from "./ShareDialog"; -import { LoadExternalDialog } from "./LoadExternalDialog"; - -const nodeTypes = { - topic: TopicNode, - task: TaskNode, - image: ImageNode, - text: TextNode, -}; - -const edgeTypes = { - floating: FloatingEdge -}; - -export interface LearningMapEditorProps { - roadmapData?: string | RoadmapData; - language?: string; - onChange?: (data: RoadmapData) => void; - jsonStore?: string; -} - -const getDefaultFilename = () => { - const now = new Date(); - const pad = (n: number) => n.toString().padStart(2, '0'); - return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}`; -}; - -export function LearningMapEditor({ - roadmapData, - language = "en", - onChange, - jsonStore = "https://json.openpatch.org", -}: LearningMapEditorProps) { - - const parsedRoadmap = parseRoadmapData(roadmapData || ""); - const { screenToFlowPosition, zoomIn, zoomOut, setCenter, fitView } = useReactFlow(); - - // Only get minimal state needed in this component - const nodes = useEditorStore(state => state.nodes); - const edges = useEditorStore(state => state.edges); - const settings = useEditorStore(state => state.settings); - const saved = useEditorStore(state => state.saved); - const previewMode = useEditorStore(state => state.previewMode); - const debugMode = useEditorStore(state => state.debugMode); - const showGrid = useEditorStore(state => state.showGrid); - const helpOpen = useEditorStore(state => state.helpOpen); - const selectedNodeId = useEditorStore(state => state.selectedNodeId); - const selectedNodeIds = useEditorStore(state => state.selectedNodeIds); - const selectedEdge = useEditorStore(state => state.selectedEdge); - const showCompletionNeeds = useEditorStore(state => state.showCompletionNeeds); - const showCompletionOptional = useEditorStore(state => state.showCompletionOptional); - const showUnlockAfter = useEditorStore(state => state.showUnlockAfter); - const lastMousePosition = useEditorStore(state => state.lastMousePosition); - const nextNodeId = useEditorStore(state => state.nextNodeId); - const clipboard = useEditorStore(state => state.clipboard); - const pendingExternalId = useEditorStore(state => state.pendingExternalId); - - // Store actions - const onNodesChange = useEditorStore(state => state.onNodesChange); - const onEdgesChange = useEditorStore(state => state.onEdgesChange); - const onConnect = useEditorStore(state => state.onConnect); - const setSaved = useEditorStore(state => state.setSaved); - const setHelpOpen = useEditorStore(state => state.setHelpOpen); - const setShowGrid = useEditorStore(state => state.setShowGrid); - const setSelectedNodeId = useEditorStore(state => state.setSelectedNodeId); - const setSelectedNodeIds = useEditorStore(state => state.setSelectedNodeIds); - const setDrawerOpen = useEditorStore(state => state.setDrawerOpen); - const setSettingsDrawerOpen = useEditorStore(state => state.setSettingsDrawerOpen); - const setEdgeDrawerOpen = useEditorStore(state => state.setEdgeDrawerOpen); - const setSelectedEdge = useEditorStore(state => state.setSelectedEdge); - const setNextNodeId = useEditorStore(state => state.setNextNodeId); - const setClipboard = useEditorStore(state => state.setClipboard); - const setLastMousePosition = useEditorStore(state => state.setLastMousePosition); - const setShareDialogOpen = useEditorStore(state => state.setShareDialogOpen); - const setLoadExternalDialogOpen = useEditorStore(state => state.setLoadExternalDialogOpen); - const setPendingExternalId = useEditorStore(state => state.setPendingExternalId); - const setShareLink = useEditorStore(state => state.setShareLink); - const setDebugMode = useEditorStore(state => state.setDebugMode); - const setPreviewMode = useEditorStore(state => state.setPreviewMode); - const updateNode = useEditorStore(state => state.updateNode); - const updateNodes = useEditorStore(state => state.updateNodes); - const updateEdge = useEditorStore(state => state.updateEdge); - const deleteNode = useEditorStore(state => state.deleteNode); - const deleteEdge = useEditorStore(state => state.deleteEdge); - const addNode = useEditorStore(state => state.addNode); - const loadRoadmapData = useEditorStore(state => state.loadRoadmapData); - const getRoadmapData = useEditorStore(state => state.getRoadmapData); - const closeAllDrawers = useEditorStore(state => state.closeAllDrawers); - const setNodes = useEditorStore(state => state.setNodes); - const setEdges = useEditorStore(state => state.setEdges); - const setSettings = useEditorStore(state => state.setSettings); - - // Temporal store for undo/redo - const { undo, redo, canUndo, canRedo } = useTemporalStore(); - - const colorMode: ColorMode = "light"; - - // Use language from settings if available, otherwise use prop - const effectiveLanguage = settings?.language || language; - const t = getTranslations(effectiveLanguage); - - const keyboardShortcuts = [ - { action: t.shortcuts.undo, shortcut: "Ctrl+Z" }, - { action: t.shortcuts.redo, shortcut: "Ctrl+Y or Ctrl+Shift+Z" }, - { action: t.shortcuts.addTaskNode, shortcut: "Ctrl+1" }, - { action: t.shortcuts.addTopicNode, shortcut: "Ctrl+2" }, - { action: t.shortcuts.addImageNode, shortcut: "Ctrl+3" }, - { action: t.shortcuts.addTextNode, shortcut: "Ctrl+4" }, - { action: t.shortcuts.deleteNodeEdge, shortcut: "Delete" }, - { action: t.shortcuts.togglePreviewMode, shortcut: "Ctrl+P" }, - { action: t.shortcuts.toggleDebugMode, shortcut: "Ctrl+D" }, - { action: t.shortcuts.selectMultipleNodes, shortcut: "Ctrl+Click or Shift+Drag" }, - { action: t.shortcuts.selectAllNodes, shortcut: "Ctrl+A" }, - { action: t.shortcuts.showHelp, shortcut: "Ctrl+? or Help Button" }, - { action: t.shortcuts.zoomIn, shortcut: "Ctrl++" }, - { action: t.shortcuts.zoomOut, shortcut: "Ctrl+-" }, - { action: t.shortcuts.resetZoom, shortcut: "Ctrl+0" }, - { action: t.shortcuts.fitView, shortcut: "Shift+1" }, - { action: t.shortcuts.zoomToSelection, shortcut: "Shift+2" }, - { action: t.shortcuts.toggleGrid, shortcut: "Ctrl+'" }, - { action: t.shortcuts.resetMap, shortcut: "Ctrl+Delete" }, - { action: t.shortcuts.cut, shortcut: "Ctrl+X" }, - { action: t.shortcuts.copy, shortcut: "Ctrl+C" }, - { action: t.shortcuts.paste, shortcut: "Ctrl+V" }, - ]; - - useEffect(() => { - loadRoadmapData(parsedRoadmap); - }, [roadmapData, loadRoadmapData]); - - useEffect(() => { - // Filter out existing debug edges, but use the store's edges directly to avoid dependency loop - const baseEdges = useEditorStore.getState().edges.filter((e) => !e.id.startsWith("debug-")); - const newEdges: Edge[] = [...baseEdges]; - - if (debugMode) { - nodes.forEach((node) => { - if (showCompletionNeeds && node.type === "topic" && node.data?.completion?.needs) { - node.data.completion.needs.forEach((needId: string) => { - const edgeId = `debug-edge-${needId}-to-${node.id}`; - newEdges.push({ - id: edgeId, - target: needId, - source: node.id, - animated: true, - style: { stroke: "#f97316", strokeWidth: 2, strokeDasharray: "5,5" }, - type: "floating", - }); - }); - } - if (showCompletionOptional && node.data?.completion?.optional) { - node.data.completion.optional.forEach((optionalId: string) => { - const edgeId = `debug-edge-optional-${optionalId}-to-${node.id}`; - newEdges.push({ - id: edgeId, - target: optionalId, - source: node.id, - animated: true, - style: { stroke: "#eab308", strokeWidth: 2, strokeDasharray: "5,5" }, - type: "floating", - }); - }); - } - }); - nodes.forEach((node) => { - if (showUnlockAfter && node.data.unlock?.after) { - node.data.unlock.after.forEach((unlockId: string) => { - const edgeId = `debug-edge-${unlockId}-to-${node.id}`; - newEdges.push({ - id: edgeId, - target: unlockId, - source: node.id, - animated: true, - style: { stroke: "#10b981", strokeWidth: 2, strokeDasharray: "5,5" }, - type: "floating", - }); - }); - } - }); - } - setEdges(newEdges); - }, [nodes, debugMode, showCompletionNeeds, showCompletionOptional, showUnlockAfter, setEdges]); - - // Event handlers - const handleNodeClick = useCallback((_: any, node: Node) => { - setSelectedNodeId(node.id); - setDrawerOpen(true); - }, [setSelectedNodeId, setDrawerOpen]); - - const handleEdgeClick = useCallback((_: any, edge: Edge) => { - setSelectedEdge(edge); - setEdgeDrawerOpen(true); - }, [setSelectedEdge, setEdgeDrawerOpen]); - - const closeDrawer = useCallback(() => { - closeAllDrawers(); - }, [closeAllDrawers]); - - const handleUpdateNode = useCallback( - (updatedNode: Node) => { - updateNode(updatedNode.id, updatedNode); - }, - [updateNode] - ); - - const handleUpdateNodes = useCallback( - (updatedNodes: Node[]) => { - updateNodes(updatedNodes); - }, - [updateNodes] - ); - - const handleUpdateEdge = useCallback( - (updatedEdge: Edge) => { - updateEdge(updatedEdge.id, updatedEdge); - }, - [updateEdge] - ); - - // Delete selected edge - const handleDeleteEdge = useCallback(() => { - if (!selectedEdge) return; - deleteEdge(selectedEdge.id); - closeAllDrawers(); - }, [selectedEdge, deleteEdge, closeAllDrawers]); - - const handleDeleteNode = useCallback(() => { - if (!selectedNodeId) return; - deleteNode(selectedNodeId); - closeAllDrawers(); - }, [selectedNodeId, deleteNode, closeAllDrawers]); - - const addNewNode = useCallback( - (type: "task" | "topic" | "image" | "text") => { - // Use last mouse position if available, otherwise use center of screen - const position = lastMousePosition - ? screenToFlowPosition(lastMousePosition) - : screenToFlowPosition({ x: window.innerWidth / 2, y: window.innerHeight / 2 }); - - if (type === "task") { - const newNode: Node = { - id: `node${nextNodeId}`, - type, - position, - data: { - label: t.newTask, - summary: "", - description: "", - }, - }; - addNode(newNode); - setNextNodeId(nextNodeId + 1); - } else if (type === "topic") { - const newNode: Node = { - id: `node${nextNodeId}`, - type, - position, - data: { - label: t.newTopic, - summary: "", - description: "", - }, - }; - addNode(newNode); - setNextNodeId(nextNodeId + 1); - } - else if (type === "image") { - const newNode: Node = { - id: `background-node${nextNodeId}`, - type, - zIndex: -2, - position, - data: { - src: "", - }, - }; - addNode(newNode); - setNextNodeId(nextNodeId + 1); - } else if (type === "text") { - const newNode: Node = { - id: `background-node${nextNodeId}`, - type, - position, - zIndex: -1, - data: { - text: t.backgroundTextDefault, - fontSize: 32, - color: "#e5e7eb", - }, - }; - addNode(newNode); - setNextNodeId(nextNodeId + 1); - } - }, - [nextNodeId, lastMousePosition, screenToFlowPosition, addNode, setNextNodeId, t] - ); - - const handleSave = useCallback(() => { - const roadmapData = getRoadmapData(); - setSaved(true); - - if (onChange) { - onChange(roadmapData); - return; - } else { - const root = document.querySelector("hyperbook-learningmap-editor"); - if (root) { - root.dispatchEvent(new CustomEvent("change", { detail: roadmapData })); - } - } - }, [nodes, edges, settings, onChange, getRoadmapData, setSaved]); - - // Auto-save when changes are made - useEffect(() => { - if (!saved) { - setTimeout(() => { - handleSave(); - }, 2000); - } - }, [saved, handleSave]); - - const togglePreviewMode = useCallback(() => { - handleSave(); - const newMode = !previewMode; - setPreviewMode(newMode); - if (newMode) { - setDebugMode(false); - closeDrawer(); - } - }, [previewMode, setPreviewMode, setDebugMode, handleSave, closeDrawer]); - - const toggleDebugMode = useCallback(() => { - setDebugMode(!debugMode); - }, [debugMode, setDebugMode]); - - const handleDownload = useCallback(() => { - const roadmapData = getRoadmapData(); - const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(roadmapData, null, 2)); - const downloadAnchorNode = document.createElement('a'); - downloadAnchorNode.setAttribute("href", dataStr); - downloadAnchorNode.setAttribute("download", `${roadmapData.settings.title?.trim() ?? getDefaultFilename()}.learningmap`); - document.body.appendChild(downloadAnchorNode); // required for firefox - downloadAnchorNode.click(); - downloadAnchorNode.remove(); - }, [getRoadmapData]); - - const handleShare = useCallback(() => { - const roadmapData = getRoadmapData(); - - // Check if map is empty (no nodes) - if (!roadmapData.nodes || roadmapData.nodes.length === 0) { - alert(t.emptyMapCannotBeShared); - return; - } - - // Upload to JSON store - fetch(`${jsonStore}/api/v2/post`, { - method: "POST", - mode: "cors", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(roadmapData), - }) - .then((r) => r.json()) - .then((json) => { - const link = window.location.origin + window.location.pathname + "#json=" + json.id; - setShareLink(link); - setShareDialogOpen(true); - }) - .catch(() => { - alert(t.uploadFailed); - }); - }, [getRoadmapData, jsonStore, t, setShareLink, setShareDialogOpen]); - - const loadFromJsonStore = useCallback((id: string) => { - fetch(`${jsonStore}/api/v2/${id}`, { - method: "GET", - mode: "cors", - }) - .then((r) => r.text()) - .then((text) => { - const json = JSON.parse(text); - loadRoadmapData(json); - setLoadExternalDialogOpen(false); - setPendingExternalId(null); - }) - .catch(() => { - alert(t.loadFailed); - }); - }, [jsonStore, t, loadRoadmapData, setLoadExternalDialogOpen, setPendingExternalId]); - - const handleLoadExternal = useCallback((id: string) => { - setPendingExternalId(id); - setLoadExternalDialogOpen(true); - }, [setPendingExternalId, setLoadExternalDialogOpen]); - - // Check for external JSON in URL hash on mount - useEffect(() => { - const hash = window.location.hash; - if (hash.startsWith("#json=")) { - const id = hash.substring(6); - handleLoadExternal(id); - } - }, [handleLoadExternal]); - - - const defaultEdgeOptions = { - animated: false, - style: { - stroke: "#94a3b8", - strokeWidth: 2, - }, - type: "default", - }; - - const handleOpen = useCallback(() => { - const input = document.createElement('input'); - input.type = 'file'; - input.accept = '.learningmap,application/json'; - input.onchange = (e: any) => { - const file = e.target.files[0]; - if (!file) return; - - if (!window.confirm(t.openFileWarning)) { - return; - } - - const reader = new FileReader(); - reader.onload = (evt) => { - try { - const content = evt.target?.result; - if (typeof content === 'string') { - const json = JSON.parse(content); - loadRoadmapData(json); - } - } catch (err) { - alert(t.failedToLoadFile); - } - }; - reader.readAsText(file); - }; - input.click(); - }, [loadRoadmapData, t]); - - // Toolbar handler wrappers for EditorToolbar props - const handleOpenSettingsDrawer = useCallback(() => setSettingsDrawerOpen(true), [setSettingsDrawerOpen]); - - const handleNodesChange: OnNodesChange = useCallback( - (changes) => { - onNodesChange(changes); - }, - [onNodesChange] - ); - - const handleEdgesChange: OnEdgesChange = useCallback( - (changes) => { - onEdgesChange(changes); - }, - [onEdgesChange] - ); - - const handleUndo = useCallback(() => { - if (canUndo) { - undo(); - } - }, [canUndo, undo]); - - const handleRedo = useCallback(() => { - if (canRedo) { - redo(); - } - }, [canRedo, redo]); - - const handleCut = useCallback(() => { - const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); - if (selectedNodes.length > 0) { - const selectedNodeIdSet = new Set(selectedNodeIds); - const relatedEdges = edges.filter(e => - selectedNodeIdSet.has(e.source) && selectedNodeIdSet.has(e.target) - ); - setClipboard({ nodes: selectedNodes, edges: relatedEdges }); - // Delete the selected nodes - selectedNodeIds.forEach(id => deleteNode(id)); - setSelectedNodeIds([]); - } - }, [nodes, edges, selectedNodeIds, deleteNode, setSelectedNodeIds, setClipboard]); - - const handleCopy = useCallback(() => { - const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); - if (selectedNodes.length > 0) { - const selectedNodeIdSet = new Set(selectedNodeIds); - const relatedEdges = edges.filter(e => - selectedNodeIdSet.has(e.source) && selectedNodeIdSet.has(e.target) - ); - setClipboard({ nodes: selectedNodes, edges: relatedEdges }); - } - }, [nodes, edges, selectedNodeIds, setClipboard]); - - const handlePaste = useCallback(() => { - if (!clipboard) return; - - // Create a mapping from old node IDs to new node IDs - const idMapping: Record = {}; - let newNextNodeId = nextNodeId; - - const newNodes = clipboard.nodes.map(node => { - const newId = node.id.startsWith('background-node') - ? `background-node${newNextNodeId}` - : `node${newNextNodeId}`; - idMapping[node.id] = newId; - newNextNodeId++; - - return { - ...node, - id: newId, - position: { - x: node.position.x + 50, - y: node.position.y + 50, - }, - }; - }); - - const newEdges = clipboard.edges.map((edge, idx) => ({ - ...edge, - id: `e${Date.now()}-${idx}`, - source: idMapping[edge.source] || edge.source, - target: idMapping[edge.target] || edge.target, - })); - - newNodes.forEach(node => addNode(node)); - setEdges([...edges, ...newEdges]); - setNextNodeId(newNextNodeId); - setSelectedNodeIds(newNodes.map(n => n.id)); - }, [clipboard, nextNodeId, edges, addNode, setEdges, setNextNodeId, setSelectedNodeIds]); - - const handleZoomIn = useCallback(() => { - zoomIn(); - }, [zoomIn]); - - const handleZoomOut = useCallback(() => { - zoomOut(); - }, [zoomOut]); - - const handleResetZoom = useCallback(() => { - setCenter(0, 0, { zoom: 1, duration: 300 }); - }, [setCenter]); - - const handleFitView = useCallback(() => { - fitView({ duration: 300 }); - }, [fitView]); - - const handleZoomToSelection = useCallback(() => { - if (selectedNodeIds.length > 0) { - fitView({ nodes: selectedNodeIds.map(s => ({ id: s })), duration: 300, padding: 0.2 }); - } - }, [selectedNodeIds, fitView]); - - const handleToggleGrid = useCallback(() => { - setShowGrid(!showGrid); - }, [showGrid, setShowGrid]); - - const handleResetMap = useCallback(() => { - if (confirm(t.resetMapWarning)) { - setNodes([]); - setEdges([]); - setNextNodeId(1); - } - }, [setNodes, setEdges, setNextNodeId, t]); - - const handleSelectAll = useCallback(() => { - setSelectedNodeIds(nodes.map(n => n.id)); - }, [nodes, setSelectedNodeIds]); - - const handleSelectionChange: OnSelectionChangeFunc = useCallback( - ({ nodes: selectedNodes }) => { - setSelectedNodeIds(selectedNodes.map(n => n.id)); - }, - [setSelectedNodeIds] - ); - - // Track mouse position for node placement - useEffect(() => { - const handleMouseMove = (e: MouseEvent) => { - setLastMousePosition({ x: e.clientX, y: e.clientY }); - }; - window.addEventListener("mousemove", handleMouseMove); - return () => { - window.removeEventListener("mousemove", handleMouseMove); - }; - }, []); - - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - //save shortcut - if ((e.ctrlKey || e.metaKey) && e.key === 's' && !e.shiftKey) { - e.preventDefault(); - handleSave(); - } - // undo shortcut - if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) { - e.preventDefault(); - handleUndo(); - } - // redo shortcut - if ((e.ctrlKey || e.metaKey) && (e.key === 'y' || (e.shiftKey && e.key === 'Z'))) { - e.preventDefault(); - handleRedo(); - } - // add task node shortcut - if ((e.ctrlKey || e.metaKey) && e.key === '1' && !e.shiftKey) { - e.preventDefault(); - addNewNode("task"); - } - // add topic node shortcut - if ((e.ctrlKey || e.metaKey) && e.key === '2' && !e.shiftKey) { - e.preventDefault(); - addNewNode("topic"); - } - // add image node shortcut - if ((e.ctrlKey || e.metaKey) && e.key === '3' && !e.shiftKey) { - e.preventDefault(); - addNewNode("image"); - } - if ((e.ctrlKey || e.metaKey) && e.key === '4' && !e.shiftKey) { - e.preventDefault(); - addNewNode("text"); - } - - if ((e.ctrlKey || e.metaKey) && (e.key === '?' || (e.shiftKey && e.key === '/'))) { - e.preventDefault(); - setHelpOpen(!helpOpen); - } - //preview toggle shortcut - if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'p' && !e.shiftKey) { - e.preventDefault(); - togglePreviewMode(); - } - //debug toggle shortcut - if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'd' && !e.shiftKey) { - e.preventDefault(); - toggleDebugMode(); - } - - // Zoom in shortcut - if ((e.ctrlKey || e.metaKey) && (e.key === '+' || e.key === '=') && !e.shiftKey) { - e.preventDefault(); - handleZoomIn(); - } - // Zoom out shortcut - if ((e.ctrlKey || e.metaKey) && (e.key === '-' || e.key === '_') && !e.shiftKey) { - e.preventDefault(); - handleZoomOut(); - } - // Reset zoom shortcut - if ((e.ctrlKey || e.metaKey) && e.key === '0' && !e.shiftKey) { - e.preventDefault(); - handleResetZoom(); - } - // Fit view shortcut - if (e.shiftKey && e.code === 'Digit1' && !e.ctrlKey && !e.metaKey) { - e.preventDefault(); - handleFitView(); - } - // Zoom to selection shortcut - if (e.shiftKey && e.code === 'Digit2' && !e.ctrlKey && !e.metaKey) { - e.preventDefault(); - handleZoomToSelection(); - } - - // Toggle grid shortcut - if ((e.ctrlKey || e.metaKey) && e.code === "Backslash") { - e.preventDefault(); - handleToggleGrid(); - } - // Reset map shortcut - if ((e.ctrlKey || e.metaKey) && e.key === 'Delete') { - e.preventDefault(); - handleResetMap(); - } - // Cut shortcut - if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'x' && !e.shiftKey) { - e.preventDefault(); - handleCut(); - } - // Copy shortcut - if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'c' && !e.shiftKey) { - e.preventDefault(); - handleCopy(); - } - // Paste shortcut - if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'v' && !e.shiftKey) { - e.preventDefault(); - handlePaste(); - } - // Select all shortcut - if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'a' && !e.shiftKey) { - e.preventDefault(); - handleSelectAll(); - } - - // Dismiss with Escape - if (helpOpen && e.key === 'Escape') { - setHelpOpen(false); - } - }; - window.addEventListener("keydown", handleKeyDown); - return () => { - window.removeEventListener("keydown", handleKeyDown); - }; - }, [handleSave, handleUndo, handleRedo, addNewNode, helpOpen, setHelpOpen, togglePreviewMode, toggleDebugMode, - handleZoomIn, handleZoomOut, handleResetZoom, handleFitView, handleZoomToSelection, handleToggleGrid, - handleResetMap, handleCut, handleCopy, handlePaste, handleSelectAll]); - - return ( - <> - - {previewMode && } - {!previewMode && <> -
- {nodes.length === 0 && edges.length === 0 && addNewNode("topic")} - onShowHelp={() => setHelpOpen(true)} - language={effectiveLanguage} - />} - - {showGrid && } - - - - - - - - - - - setHelpOpen(true)}> - - - - {!saved && { handleSave(); }}> - - } - {selectedNodeIds.length > 1 && } - -
- - - - setHelpOpen(false)} - > -
-

{t.keyboardShortcuts}

- -
-
- - - - - - - - - {keyboardShortcuts.map((item) => ( - - - - - ))} - -
{t.action}{t.shortcut}
{item.action}{item.shortcut}
-
-
- -
-
- setShareDialogOpen(false)} - language={effectiveLanguage} - /> - { - setLoadExternalDialogOpen(false); - setPendingExternalId(null); - }} - onDownloadCurrent={handleDownload} - onReplace={() => { - if (pendingExternalId) { - loadFromJsonStore(pendingExternalId); - } - }} - language={effectiveLanguage} - /> - - } - - ); -} - -export default (props: LearningMapEditorProps) => { - return ( -
- - - -
- ) -} From ff17eb86f05560e74bbc8bc3adf168dbd7ca1c51 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 11:55:27 +0000 Subject: [PATCH 13/17] Integrate new components: Use EditorCanvas, EditorDialogs, DebugModeEdges, KeyboardShortcuts Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- .../learningmap/src/LearningMapEditor.tsx | 878 ++---------------- 1 file changed, 102 insertions(+), 776 deletions(-) diff --git a/packages/learningmap/src/LearningMapEditor.tsx b/packages/learningmap/src/LearningMapEditor.tsx index 773b8d9..2a387e1 100644 --- a/packages/learningmap/src/LearningMapEditor.tsx +++ b/packages/learningmap/src/LearningMapEditor.tsx @@ -1,50 +1,23 @@ -import { useCallback, useEffect } from "react"; +import { useEffect } from "react"; import { - ReactFlow, - Controls, - ColorMode, useReactFlow, - Node, - Connection, - Edge, - Background, - ControlButton, - OnNodesChange, - OnEdgesChange, - Panel, - OnSelectionChangeFunc, ReactFlowProvider, } from "@xyflow/react"; import { EditorDrawer } from "./EditorDrawer"; import { EdgeDrawer } from "./EdgeDrawer"; -import { TaskNode } from "./nodes/TaskNode"; -import { TopicNode } from "./nodes/TopicNode"; -import { ImageNode } from "./nodes/ImageNode"; -import { TextNode } from "./nodes/TextNode"; -import { RoadmapData, NodeData, ImageNodeData, TextNodeData, Settings } from "./types"; +import { RoadmapData } from "./types"; import { SettingsDrawer } from "./SettingsDrawer"; -import FloatingEdge from "./FloatingEdge"; import { EditorToolbar } from "./EditorToolbar"; import { parseRoadmapData } from "./helper"; import { LearningMap } from "./LearningMap"; -import { Info, Redo, Undo, RotateCw, ShieldAlert, X } from "lucide-react"; -import { useEditorStore, useTemporalStore } from "./editorStore"; -import { MultiNodePanel } from "./MultiNodePanel"; +import { useEditorStore } from "./editorStore"; import { getTranslations } from "./translations"; import { WelcomeMessage } from "./WelcomeMessage"; -import { ShareDialog } from "./ShareDialog"; -import { LoadExternalDialog } from "./LoadExternalDialog"; - -const nodeTypes = { - topic: TopicNode, - task: TaskNode, - image: ImageNode, - text: TextNode, -}; - -const edgeTypes = { - floating: FloatingEdge -}; +import { EditorCanvas } from "./EditorCanvas"; +import { EditorDialogs } from "./EditorDialogs"; +import { DebugModeEdges } from "./DebugModeEdges"; +import { KeyboardShortcuts } from "./KeyboardShortcuts"; +import { useEditorActions } from "./useEditorActions"; export interface LearningMapEditorProps { roadmapData?: string | RoadmapData; @@ -53,12 +26,6 @@ export interface LearningMapEditorProps { jsonStore?: string; } -const getDefaultFilename = () => { - const now = new Date(); - const pad = (n: number) => n.toString().padStart(2, '0'); - return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}`; -}; - export function LearningMapEditor({ roadmapData, language = "en", @@ -67,72 +34,56 @@ export function LearningMapEditor({ }: LearningMapEditorProps) { const parsedRoadmap = parseRoadmapData(roadmapData || ""); - const { screenToFlowPosition, zoomIn, zoomOut, setCenter, fitView } = useReactFlow(); + const { screenToFlowPosition } = useReactFlow(); // Only get minimal state needed in this component const nodes = useEditorStore(state => state.nodes); const edges = useEditorStore(state => state.edges); const settings = useEditorStore(state => state.settings); - const saved = useEditorStore(state => state.saved); const previewMode = useEditorStore(state => state.previewMode); - const debugMode = useEditorStore(state => state.debugMode); - const showGrid = useEditorStore(state => state.showGrid); - const helpOpen = useEditorStore(state => state.helpOpen); - const selectedNodeId = useEditorStore(state => state.selectedNodeId); - const selectedNodeIds = useEditorStore(state => state.selectedNodeIds); - const selectedEdge = useEditorStore(state => state.selectedEdge); - const showCompletionNeeds = useEditorStore(state => state.showCompletionNeeds); - const showCompletionOptional = useEditorStore(state => state.showCompletionOptional); - const showUnlockAfter = useEditorStore(state => state.showUnlockAfter); - const lastMousePosition = useEditorStore(state => state.lastMousePosition); - const nextNodeId = useEditorStore(state => state.nextNodeId); - const clipboard = useEditorStore(state => state.clipboard); - const pendingExternalId = useEditorStore(state => state.pendingExternalId); // Store actions - const onNodesChange = useEditorStore(state => state.onNodesChange); - const onEdgesChange = useEditorStore(state => state.onEdgesChange); - const onConnect = useEditorStore(state => state.onConnect); - const setSaved = useEditorStore(state => state.setSaved); - const setHelpOpen = useEditorStore(state => state.setHelpOpen); - const setShowGrid = useEditorStore(state => state.setShowGrid); - const setSelectedNodeId = useEditorStore(state => state.setSelectedNodeId); - const setSelectedNodeIds = useEditorStore(state => state.setSelectedNodeIds); - const setDrawerOpen = useEditorStore(state => state.setDrawerOpen); - const setSettingsDrawerOpen = useEditorStore(state => state.setSettingsDrawerOpen); - const setEdgeDrawerOpen = useEditorStore(state => state.setEdgeDrawerOpen); - const setSelectedEdge = useEditorStore(state => state.setSelectedEdge); - const setNextNodeId = useEditorStore(state => state.setNextNodeId); - const setClipboard = useEditorStore(state => state.setClipboard); - const setLastMousePosition = useEditorStore(state => state.setLastMousePosition); - const setShareDialogOpen = useEditorStore(state => state.setShareDialogOpen); - const setLoadExternalDialogOpen = useEditorStore(state => state.setLoadExternalDialogOpen); - const setPendingExternalId = useEditorStore(state => state.setPendingExternalId); - const setShareLink = useEditorStore(state => state.setShareLink); - const setDebugMode = useEditorStore(state => state.setDebugMode); - const setPreviewMode = useEditorStore(state => state.setPreviewMode); - const updateNode = useEditorStore(state => state.updateNode); - const updateNodes = useEditorStore(state => state.updateNodes); - const updateEdge = useEditorStore(state => state.updateEdge); - const deleteNode = useEditorStore(state => state.deleteNode); - const deleteEdge = useEditorStore(state => state.deleteEdge); - const addNode = useEditorStore(state => state.addNode); const loadRoadmapData = useEditorStore(state => state.loadRoadmapData); const getRoadmapData = useEditorStore(state => state.getRoadmapData); - const closeAllDrawers = useEditorStore(state => state.closeAllDrawers); - const setNodes = useEditorStore(state => state.setNodes); - const setEdges = useEditorStore(state => state.setEdges); + const setHelpOpen = useEditorStore(state => state.setHelpOpen); const setSettings = useEditorStore(state => state.setSettings); - - // Temporal store for undo/redo - const { undo, redo, canUndo, canRedo } = useTemporalStore(); - - const colorMode: ColorMode = "light"; // Use language from settings if available, otherwise use prop const effectiveLanguage = settings?.language || language; const t = getTranslations(effectiveLanguage); + // Use the custom hook for all editor actions + const { + handleNodeClick, + handleEdgeClick, + closeDrawer, + handleUpdateNode, + handleUpdateEdge, + handleDeleteEdge, + handleDeleteNode, + addNewNode, + togglePreviewMode, + toggleDebugMode, + handleDownload, + handleShare, + loadFromJsonStore, + handleOpen, + handleOpenSettingsDrawer, + handleCut, + handleCopy, + handlePaste, + handleZoomIn, + handleZoomOut, + handleResetZoom, + handleFitView, + handleZoomToSelection, + handleToggleGrid, + handleResetMap, + handleSelectAll, + handleDeleteSelected, + handleSave, + } = useEditorActions(t, screenToFlowPosition, jsonStore); + const keyboardShortcuts = [ { action: t.shortcuts.undo, shortcut: "Ctrl+Z" }, { action: t.shortcuts.redo, shortcut: "Ctrl+Y or Ctrl+Shift+Z" }, @@ -146,608 +97,60 @@ export function LearningMapEditor({ { action: t.shortcuts.selectMultipleNodes, shortcut: "Ctrl+Click or Shift+Drag" }, { action: t.shortcuts.selectAllNodes, shortcut: "Ctrl+A" }, { action: t.shortcuts.showHelp, shortcut: "Ctrl+? or Help Button" }, + { action: t.shortcuts.save, shortcut: "Ctrl+S" }, { action: t.shortcuts.zoomIn, shortcut: "Ctrl++" }, { action: t.shortcuts.zoomOut, shortcut: "Ctrl+-" }, { action: t.shortcuts.resetZoom, shortcut: "Ctrl+0" }, - { action: t.shortcuts.fitView, shortcut: "Shift+1" }, - { action: t.shortcuts.zoomToSelection, shortcut: "Shift+2" }, - { action: t.shortcuts.toggleGrid, shortcut: "Ctrl+'" }, { action: t.shortcuts.resetMap, shortcut: "Ctrl+Delete" }, + { action: t.shortcuts.fitView, shortcut: "Shift+!" }, + { action: t.shortcuts.zoomToSelection, shortcut: "Shift+@" }, + { action: t.shortcuts.toggleGrid, shortcut: "Ctrl+'" }, { action: t.shortcuts.cut, shortcut: "Ctrl+X" }, { action: t.shortcuts.copy, shortcut: "Ctrl+C" }, { action: t.shortcuts.paste, shortcut: "Ctrl+V" }, ]; + // Load roadmap data when prop changes useEffect(() => { loadRoadmapData(parsedRoadmap); }, [roadmapData, loadRoadmapData]); + // Save changes via onChange callback useEffect(() => { - // Filter out existing debug edges, but use the store's edges directly to avoid dependency loop - const baseEdges = useEditorStore.getState().edges.filter((e) => !e.id.startsWith("debug-")); - const newEdges: Edge[] = [...baseEdges]; - - if (debugMode) { - nodes.forEach((node) => { - if (showCompletionNeeds && node.type === "topic" && node.data?.completion?.needs) { - node.data.completion.needs.forEach((needId: string) => { - const edgeId = `debug-edge-${needId}-to-${node.id}`; - newEdges.push({ - id: edgeId, - target: needId, - source: node.id, - animated: true, - style: { stroke: "#f97316", strokeWidth: 2, strokeDasharray: "5,5" }, - type: "floating", - }); - }); - } - if (showCompletionOptional && node.data?.completion?.optional) { - node.data.completion.optional.forEach((optionalId: string) => { - const edgeId = `debug-edge-optional-${optionalId}-to-${node.id}`; - newEdges.push({ - id: edgeId, - target: optionalId, - source: node.id, - animated: true, - style: { stroke: "#eab308", strokeWidth: 2, strokeDasharray: "5,5" }, - type: "floating", - }); - }); - } - }); - nodes.forEach((node) => { - if (showUnlockAfter && node.data.unlock?.after) { - node.data.unlock.after.forEach((unlockId: string) => { - const edgeId = `debug-edge-${unlockId}-to-${node.id}`; - newEdges.push({ - id: edgeId, - target: unlockId, - source: node.id, - animated: true, - style: { stroke: "#10b981", strokeWidth: 2, strokeDasharray: "5,5" }, - type: "floating", - }); - }); - } - }); - } - setEdges(newEdges); - }, [nodes, debugMode, showCompletionNeeds, showCompletionOptional, showUnlockAfter, setEdges]); - - // Event handlers - const handleNodeClick = useCallback((_: any, node: Node) => { - setSelectedNodeId(node.id); - setDrawerOpen(true); - }, [setSelectedNodeId, setDrawerOpen]); - - const handleEdgeClick = useCallback((_: any, edge: Edge) => { - setSelectedEdge(edge); - setEdgeDrawerOpen(true); - }, [setSelectedEdge, setEdgeDrawerOpen]); - - const closeDrawer = useCallback(() => { - closeAllDrawers(); - }, [closeAllDrawers]); - - const handleUpdateNode = useCallback( - (updatedNode: Node) => { - updateNode(updatedNode.id, updatedNode); - }, - [updateNode] - ); - - const handleUpdateNodes = useCallback( - (updatedNodes: Node[]) => { - updateNodes(updatedNodes); - }, - [updateNodes] - ); - - const handleUpdateEdge = useCallback( - (updatedEdge: Edge) => { - updateEdge(updatedEdge.id, updatedEdge); - }, - [updateEdge] - ); - - // Delete selected edge - const handleDeleteEdge = useCallback(() => { - if (!selectedEdge) return; - deleteEdge(selectedEdge.id); - closeAllDrawers(); - }, [selectedEdge, deleteEdge, closeAllDrawers]); - - const handleDeleteNode = useCallback(() => { - if (!selectedNodeId) return; - deleteNode(selectedNodeId); - closeAllDrawers(); - }, [selectedNodeId, deleteNode, closeAllDrawers]); - - const addNewNode = useCallback( - (type: "task" | "topic" | "image" | "text") => { - // Use last mouse position if available, otherwise use center of screen - const position = lastMousePosition - ? screenToFlowPosition(lastMousePosition) - : screenToFlowPosition({ x: window.innerWidth / 2, y: window.innerHeight / 2 }); - - if (type === "task") { - const newNode: Node = { - id: `node${nextNodeId}`, - type, - position, - data: { - label: t.newTask, - summary: "", - description: "", - }, - }; - addNode(newNode); - setNextNodeId(nextNodeId + 1); - } else if (type === "topic") { - const newNode: Node = { - id: `node${nextNodeId}`, - type, - position, - data: { - label: t.newTopic, - summary: "", - description: "", - }, - }; - addNode(newNode); - setNextNodeId(nextNodeId + 1); - } - else if (type === "image") { - const newNode: Node = { - id: `background-node${nextNodeId}`, - type, - zIndex: -2, - position, - data: { - src: "", - }, - }; - addNode(newNode); - setNextNodeId(nextNodeId + 1); - } else if (type === "text") { - const newNode: Node = { - id: `background-node${nextNodeId}`, - type, - position, - zIndex: -1, - data: { - text: t.backgroundTextDefault, - fontSize: 32, - color: "#e5e7eb", - }, - }; - addNode(newNode); - setNextNodeId(nextNodeId + 1); - } - }, - [nextNodeId, lastMousePosition, screenToFlowPosition, addNode, setNextNodeId, t] - ); - - const handleSave = useCallback(() => { - const roadmapData = getRoadmapData(); - setSaved(true); - if (onChange) { + const roadmapData = getRoadmapData(); onChange(roadmapData); - return; - } else { - const root = document.querySelector("hyperbook-learningmap-editor"); - if (root) { - root.dispatchEvent(new CustomEvent("change", { detail: roadmapData })); - } - } - }, [nodes, edges, settings, onChange, getRoadmapData, setSaved]); - - // Auto-save when changes are made - useEffect(() => { - if (!saved) { - setTimeout(() => { - handleSave(); - }, 2000); - } - }, [saved, handleSave]); - - const togglePreviewMode = useCallback(() => { - handleSave(); - const newMode = !previewMode; - setPreviewMode(newMode); - if (newMode) { - setDebugMode(false); - closeDrawer(); - } - }, [previewMode, setPreviewMode, setDebugMode, handleSave, closeDrawer]); - - const toggleDebugMode = useCallback(() => { - setDebugMode(!debugMode); - }, [debugMode, setDebugMode]); - - const handleDownload = useCallback(() => { - const roadmapData = getRoadmapData(); - const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(roadmapData, null, 2)); - const downloadAnchorNode = document.createElement('a'); - downloadAnchorNode.setAttribute("href", dataStr); - downloadAnchorNode.setAttribute("download", `${roadmapData.settings.title?.trim() ?? getDefaultFilename()}.learningmap`); - document.body.appendChild(downloadAnchorNode); // required for firefox - downloadAnchorNode.click(); - downloadAnchorNode.remove(); - }, [getRoadmapData]); - - const handleShare = useCallback(() => { - const roadmapData = getRoadmapData(); - - // Check if map is empty (no nodes) - if (!roadmapData.nodes || roadmapData.nodes.length === 0) { - alert(t.emptyMapCannotBeShared); - return; - } - - // Upload to JSON store - fetch(`${jsonStore}/api/v2/post`, { - method: "POST", - mode: "cors", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(roadmapData), - }) - .then((r) => r.json()) - .then((json) => { - const link = window.location.origin + window.location.pathname + "#json=" + json.id; - setShareLink(link); - setShareDialogOpen(true); - }) - .catch(() => { - alert(t.uploadFailed); - }); - }, [getRoadmapData, jsonStore, t, setShareLink, setShareDialogOpen]); - - const loadFromJsonStore = useCallback((id: string) => { - fetch(`${jsonStore}/api/v2/${id}`, { - method: "GET", - mode: "cors", - }) - .then((r) => r.text()) - .then((text) => { - const json = JSON.parse(text); - loadRoadmapData(json); - setLoadExternalDialogOpen(false); - setPendingExternalId(null); - }) - .catch(() => { - alert(t.loadFailed); - }); - }, [jsonStore, t, loadRoadmapData, setLoadExternalDialogOpen, setPendingExternalId]); - - const handleLoadExternal = useCallback((id: string) => { - setPendingExternalId(id); - setLoadExternalDialogOpen(true); - }, [setPendingExternalId, setLoadExternalDialogOpen]); - - // Check for external JSON in URL hash on mount - useEffect(() => { - const hash = window.location.hash; - if (hash.startsWith("#json=")) { - const id = hash.substring(6); - handleLoadExternal(id); - } - }, [handleLoadExternal]); - - - const defaultEdgeOptions = { - animated: false, - style: { - stroke: "#94a3b8", - strokeWidth: 2, - }, - type: "default", - }; - - const handleOpen = useCallback(() => { - const input = document.createElement('input'); - input.type = 'file'; - input.accept = '.learningmap,application/json'; - input.onchange = (e: any) => { - const file = e.target.files[0]; - if (!file) return; - - if (!window.confirm(t.openFileWarning)) { - return; - } - - const reader = new FileReader(); - reader.onload = (evt) => { - try { - const content = evt.target?.result; - if (typeof content === 'string') { - const json = JSON.parse(content); - loadRoadmapData(json); - } - } catch (err) { - alert(t.failedToLoadFile); - } - }; - reader.readAsText(file); - }; - input.click(); - }, [loadRoadmapData, t]); - - // Toolbar handler wrappers for EditorToolbar props - const handleOpenSettingsDrawer = useCallback(() => setSettingsDrawerOpen(true), [setSettingsDrawerOpen]); - - const handleNodesChange: OnNodesChange = useCallback( - (changes) => { - onNodesChange(changes); - }, - [onNodesChange] - ); - - const handleEdgesChange: OnEdgesChange = useCallback( - (changes) => { - onEdgesChange(changes); - }, - [onEdgesChange] - ); - - const handleUndo = useCallback(() => { - if (canUndo) { - undo(); - } - }, [canUndo, undo]); - - const handleRedo = useCallback(() => { - if (canRedo) { - redo(); - } - }, [canRedo, redo]); - - const handleCut = useCallback(() => { - const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); - if (selectedNodes.length > 0) { - const selectedNodeIdSet = new Set(selectedNodeIds); - const relatedEdges = edges.filter(e => - selectedNodeIdSet.has(e.source) && selectedNodeIdSet.has(e.target) - ); - setClipboard({ nodes: selectedNodes, edges: relatedEdges }); - // Delete the selected nodes - selectedNodeIds.forEach(id => deleteNode(id)); - setSelectedNodeIds([]); - } - }, [nodes, edges, selectedNodeIds, deleteNode, setSelectedNodeIds, setClipboard]); - - const handleCopy = useCallback(() => { - const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); - if (selectedNodes.length > 0) { - const selectedNodeIdSet = new Set(selectedNodeIds); - const relatedEdges = edges.filter(e => - selectedNodeIdSet.has(e.source) && selectedNodeIdSet.has(e.target) - ); - setClipboard({ nodes: selectedNodes, edges: relatedEdges }); - } - }, [nodes, edges, selectedNodeIds, setClipboard]); - - const handlePaste = useCallback(() => { - if (!clipboard) return; - - // Create a mapping from old node IDs to new node IDs - const idMapping: Record = {}; - let newNextNodeId = nextNodeId; - - const newNodes = clipboard.nodes.map(node => { - const newId = node.id.startsWith('background-node') - ? `background-node${newNextNodeId}` - : `node${newNextNodeId}`; - idMapping[node.id] = newId; - newNextNodeId++; - - return { - ...node, - id: newId, - position: { - x: node.position.x + 50, - y: node.position.y + 50, - }, - }; - }); - - const newEdges = clipboard.edges.map((edge, idx) => ({ - ...edge, - id: `e${Date.now()}-${idx}`, - source: idMapping[edge.source] || edge.source, - target: idMapping[edge.target] || edge.target, - })); - - newNodes.forEach(node => addNode(node)); - setEdges([...edges, ...newEdges]); - setNextNodeId(newNextNodeId); - setSelectedNodeIds(newNodes.map(n => n.id)); - }, [clipboard, nextNodeId, edges, addNode, setEdges, setNextNodeId, setSelectedNodeIds]); - - const handleZoomIn = useCallback(() => { - zoomIn(); - }, [zoomIn]); - - const handleZoomOut = useCallback(() => { - zoomOut(); - }, [zoomOut]); - - const handleResetZoom = useCallback(() => { - setCenter(0, 0, { zoom: 1, duration: 300 }); - }, [setCenter]); - - const handleFitView = useCallback(() => { - fitView({ duration: 300 }); - }, [fitView]); - - const handleZoomToSelection = useCallback(() => { - if (selectedNodeIds.length > 0) { - fitView({ nodes: selectedNodeIds.map(s => ({ id: s })), duration: 300, padding: 0.2 }); - } - }, [selectedNodeIds, fitView]); - - const handleToggleGrid = useCallback(() => { - setShowGrid(!showGrid); - }, [showGrid, setShowGrid]); - - const handleResetMap = useCallback(() => { - if (confirm(t.resetMapWarning)) { - setNodes([]); - setEdges([]); - setNextNodeId(1); } - }, [setNodes, setEdges, setNextNodeId, t]); - - const handleSelectAll = useCallback(() => { - setSelectedNodeIds(nodes.map(n => n.id)); - }, [nodes, setSelectedNodeIds]); - - const handleSelectionChange: OnSelectionChangeFunc = useCallback( - ({ nodes: selectedNodes }) => { - setSelectedNodeIds(selectedNodes.map(n => n.id)); - }, - [setSelectedNodeIds] - ); - - // Track mouse position for node placement - useEffect(() => { - const handleMouseMove = (e: MouseEvent) => { - setLastMousePosition({ x: e.clientX, y: e.clientY }); - }; - window.addEventListener("mousemove", handleMouseMove); - return () => { - window.removeEventListener("mousemove", handleMouseMove); - }; - }, []); - - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - //save shortcut - if ((e.ctrlKey || e.metaKey) && e.key === 's' && !e.shiftKey) { - e.preventDefault(); - handleSave(); - } - // undo shortcut - if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) { - e.preventDefault(); - handleUndo(); - } - // redo shortcut - if ((e.ctrlKey || e.metaKey) && (e.key === 'y' || (e.shiftKey && e.key === 'Z'))) { - e.preventDefault(); - handleRedo(); - } - // add task node shortcut - if ((e.ctrlKey || e.metaKey) && e.key === '1' && !e.shiftKey) { - e.preventDefault(); - addNewNode("task"); - } - // add topic node shortcut - if ((e.ctrlKey || e.metaKey) && e.key === '2' && !e.shiftKey) { - e.preventDefault(); - addNewNode("topic"); - } - // add image node shortcut - if ((e.ctrlKey || e.metaKey) && e.key === '3' && !e.shiftKey) { - e.preventDefault(); - addNewNode("image"); - } - if ((e.ctrlKey || e.metaKey) && e.key === '4' && !e.shiftKey) { - e.preventDefault(); - addNewNode("text"); - } - - if ((e.ctrlKey || e.metaKey) && (e.key === '?' || (e.shiftKey && e.key === '/'))) { - e.preventDefault(); - setHelpOpen(!helpOpen); - } - //preview toggle shortcut - if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'p' && !e.shiftKey) { - e.preventDefault(); - togglePreviewMode(); - } - //debug toggle shortcut - if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'd' && !e.shiftKey) { - e.preventDefault(); - toggleDebugMode(); - } - - // Zoom in shortcut - if ((e.ctrlKey || e.metaKey) && (e.key === '+' || e.key === '=') && !e.shiftKey) { - e.preventDefault(); - handleZoomIn(); - } - // Zoom out shortcut - if ((e.ctrlKey || e.metaKey) && (e.key === '-' || e.key === '_') && !e.shiftKey) { - e.preventDefault(); - handleZoomOut(); - } - // Reset zoom shortcut - if ((e.ctrlKey || e.metaKey) && e.key === '0' && !e.shiftKey) { - e.preventDefault(); - handleResetZoom(); - } - // Fit view shortcut - if (e.shiftKey && e.code === 'Digit1' && !e.ctrlKey && !e.metaKey) { - e.preventDefault(); - handleFitView(); - } - // Zoom to selection shortcut - if (e.shiftKey && e.code === 'Digit2' && !e.ctrlKey && !e.metaKey) { - e.preventDefault(); - handleZoomToSelection(); - } - - // Toggle grid shortcut - if ((e.ctrlKey || e.metaKey) && e.code === "Backslash") { - e.preventDefault(); - handleToggleGrid(); - } - // Reset map shortcut - if ((e.ctrlKey || e.metaKey) && e.key === 'Delete') { - e.preventDefault(); - handleResetMap(); - } - // Cut shortcut - if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'x' && !e.shiftKey) { - e.preventDefault(); - handleCut(); - } - // Copy shortcut - if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'c' && !e.shiftKey) { - e.preventDefault(); - handleCopy(); - } - // Paste shortcut - if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'v' && !e.shiftKey) { - e.preventDefault(); - handlePaste(); - } - // Select all shortcut - if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'a' && !e.shiftKey) { - e.preventDefault(); - handleSelectAll(); - } - - // Dismiss with Escape - if (helpOpen && e.key === 'Escape') { - setHelpOpen(false); - } - }; - window.addEventListener("keydown", handleKeyDown); - return () => { - window.removeEventListener("keydown", handleKeyDown); - }; - }, [handleSave, handleUndo, handleRedo, addNewNode, helpOpen, setHelpOpen, togglePreviewMode, toggleDebugMode, - handleZoomIn, handleZoomOut, handleResetZoom, handleFitView, handleZoomToSelection, handleToggleGrid, - handleResetMap, handleCut, handleCopy, handlePaste, handleSelectAll]); + }, [nodes, edges, settings, onChange, getRoadmapData]); return ( <> + {/* Debug mode edges effect */} + + + {/* Keyboard shortcuts handler */} + {}} // Handled by EditorCanvas + onRedo={() => {}} // Handled by EditorCanvas + onTogglePreview={togglePreviewMode} + onToggleDebug={toggleDebugMode} + onResetMap={handleResetMap} + onCut={handleCut} + onCopy={handleCopy} + onPaste={handlePaste} + onSelectAll={handleSelectAll} + onZoomIn={handleZoomIn} + onZoomOut={handleZoomOut} + onResetZoom={handleResetZoom} + onFitView={handleFitView} + onZoomToSelection={handleZoomToSelection} + onToggleGrid={handleToggleGrid} + /> + + {/* Toolbar */} + + {/* Preview or Edit mode */} {previewMode && } {!previewMode && <> -
- {nodes.length === 0 && edges.length === 0 && addNewNode("topic")} - onShowHelp={() => setHelpOpen(true)} - language={effectiveLanguage} - />} - - {showGrid && } - - - - - - - - - - - setHelpOpen(true)}> - - - - {!saved && { handleSave(); }}> - - } - {selectedNodeIds.length > 1 && } - -
+ {/* Welcome message when empty */} + {nodes.length === 0 && edges.length === 0 && addNewNode("topic")} + onShowHelp={() => setHelpOpen(true)} + language={effectiveLanguage} + />} + + {/* Main canvas */} + + + {/* Drawers */} - setHelpOpen(false)} - > -
-

{t.keyboardShortcuts}

- -
-
- - - - - - - - - {keyboardShortcuts.map((item) => ( - - - - - ))} - -
{t.action}{t.shortcut}
{item.action}{item.shortcut}
-
-
- -
-
- setShareDialogOpen(false)} - language={effectiveLanguage} - /> - { - setLoadExternalDialogOpen(false); - setPendingExternalId(null); - }} - onDownloadCurrent={handleDownload} - onReplace={() => { - if (pendingExternalId) { - loadFromJsonStore(pendingExternalId); - } - }} + + {/* Dialogs */} + - - } + } ); } From ae4811ab9042b973747e39eee184f1a78d608852 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 12:07:35 +0000 Subject: [PATCH 14/17] Fix undo/redo: Properly implement useTemporalStore hook Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- packages/learningmap/src/EditorCanvas.tsx | 7 ++++++- packages/learningmap/src/editorStore.ts | 23 +++++++---------------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/packages/learningmap/src/EditorCanvas.tsx b/packages/learningmap/src/EditorCanvas.tsx index e3ca6a2..bd3a0a5 100644 --- a/packages/learningmap/src/EditorCanvas.tsx +++ b/packages/learningmap/src/EditorCanvas.tsx @@ -47,7 +47,12 @@ export const EditorCanvas = memo(({ onNodeClick, onEdgeClick, onSave, language = const updateNodes = useEditorStore(state => state.updateNodes); // Temporal store for undo/redo - const { undo, redo, canUndo, canRedo } = useTemporalStore(); + const { undo, redo } = useTemporalStore((state) => ({ + undo: state.undo, + redo: state.redo, + })); + const canUndo = useTemporalStore((state) => state.pastStates.length > 0); + const canRedo = useTemporalStore((state) => state.futureStates.length > 0); const handleNodesChange: OnNodesChange = useCallback( (changes) => { diff --git a/packages/learningmap/src/editorStore.ts b/packages/learningmap/src/editorStore.ts index 14985e7..cd7ec48 100644 --- a/packages/learningmap/src/editorStore.ts +++ b/packages/learningmap/src/editorStore.ts @@ -1,5 +1,7 @@ import { create } from 'zustand'; import { temporal } from 'zundo'; +import { useStoreWithEqualityFn } from 'zustand/traditional'; +import type { TemporalState } from 'zundo'; import { Node, Edge, applyNodeChanges, applyEdgeChanges, addEdge, NodeChange, EdgeChange, Connection } from '@xyflow/react'; import { NodeData, RoadmapData, Settings, ImageNodeData, TextNodeData } from './types'; @@ -322,20 +324,9 @@ export const useEditorStore = create()( ); // Hook for accessing temporal store (undo/redo) -import { useStore } from 'zustand'; - -export const useTemporalStore = () => { - const undo = useEditorStore.temporal.getState().undo; - const redo = useEditorStore.temporal.getState().redo; - const pastStates = useStore(useEditorStore.temporal, (state) => state.pastStates); - const futureStates = useStore(useEditorStore.temporal, (state) => state.futureStates); - - return { - undo, - redo, - pastStates, - futureStates, - canUndo: pastStates.length > 0, - canRedo: futureStates.length > 0, - }; +export const useTemporalStore = ( + selector?: (state: TemporalState) => T, + equality?: (a: T, b: T) => boolean +) => { + return useStoreWithEqualityFn(useEditorStore.temporal, selector as any, equality); }; From 1f5fe83d9c9205b29fe1d465ed1701ef3bf97136 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 12:26:15 +0000 Subject: [PATCH 15/17] Remove all store-derived props from child components - complete performance optimization Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- packages/learningmap/src/EdgeDrawer.tsx | 42 +- packages/learningmap/src/EditorCanvas.tsx | 55 +- packages/learningmap/src/EditorDialogs.tsx | 72 +- packages/learningmap/src/EditorDrawer.tsx | 42 +- packages/learningmap/src/EditorToolbar.tsx | 94 +- .../learningmap/src/KeyboardShortcuts.tsx | 186 +- .../learningmap/src/LearningMapEditor.tsx | 135 +- .../learningmap/src/LoadExternalDialog.tsx | 8 +- packages/learningmap/src/MultiNodePanel.tsx | 28 +- packages/learningmap/src/SettingsDrawer.tsx | 23 +- packages/learningmap/src/ShareDialog.tsx | 15 +- packages/learningmap/src/WelcomeMessage.tsx | 58 +- pnpm-lock.yaml | 4826 ++++++++--------- 13 files changed, 2665 insertions(+), 2919 deletions(-) diff --git a/packages/learningmap/src/EdgeDrawer.tsx b/packages/learningmap/src/EdgeDrawer.tsx index 968ce10..e514a56 100644 --- a/packages/learningmap/src/EdgeDrawer.tsx +++ b/packages/learningmap/src/EdgeDrawer.tsx @@ -6,23 +6,41 @@ import { getTranslations } from "./translations"; import { useEditorStore } from "./editorStore"; interface EdgeDrawerProps { - onClose: () => void; - onUpdate: (edge: Edge) => void; - onDelete: () => void; - language?: string; + defaultLanguage?: string; } export const EdgeDrawer: React.FC = ({ - onClose: closeDrawer, - onUpdate: updateEdge, - onDelete: deleteEdge, - language = "en", + defaultLanguage = "en", }) => { - const t = getTranslations(language); - // Get edge and drawer state from store const selectedEdge = useEditorStore(state => state.selectedEdge); const edgeDrawerOpen = useEditorStore(state => state.edgeDrawerOpen); + const settings = useEditorStore(state => state.settings); + + // Get actions from store + const setEdgeDrawerOpen = useEditorStore(state => state.setEdgeDrawerOpen); + const setSelectedEdge = useEditorStore(state => state.setSelectedEdge); + const updateEdge = useEditorStore(state => state.updateEdge); + const deleteEdge = useEditorStore(state => state.deleteEdge); + + const language = settings?.language || defaultLanguage; + const t = getTranslations(language); + + const closeDrawer = () => { + setEdgeDrawerOpen(false); + setSelectedEdge(null); + }; + + const onUpdate = (edge: Edge) => { + updateEdge(edge.id, edge); + }; + + const onDelete = () => { + if (selectedEdge && confirm(t.resetMapWarning)) { + deleteEdge(selectedEdge.id); + closeDrawer(); + } + }; if (!selectedEdge || !edgeDrawerOpen) return null; return ( @@ -49,12 +67,12 @@ export const EdgeDrawer: React.FC = ({ } else if (field === "type") { updated = { ...updated, type: value }; } - updateEdge(updated); + onUpdate(updated); }} language={language} />
-
); diff --git a/packages/learningmap/src/EditorDialogs.tsx b/packages/learningmap/src/EditorDialogs.tsx index 372218c..f6e0c19 100644 --- a/packages/learningmap/src/EditorDialogs.tsx +++ b/packages/learningmap/src/EditorDialogs.tsx @@ -6,16 +6,13 @@ import { LoadExternalDialog } from "./LoadExternalDialog"; import { getTranslations } from "./translations"; interface EditorDialogsProps { - onDownload: () => void; - onLoadFromStore: (id: string) => void; - language?: string; - keyboardShortcuts: Array<{ action: string; shortcut: string }>; + defaultLanguage?: string; + jsonStore?: string; } -export const EditorDialogs = memo(({ onDownload, onLoadFromStore, language = "en", keyboardShortcuts }: EditorDialogsProps) => { - const t = getTranslations(language); - +export const EditorDialogs = memo(({ defaultLanguage = "en", jsonStore = "https://json.openpatch.org" }: EditorDialogsProps) => { // Get state from store + const settings = useEditorStore(state => state.settings); const helpOpen = useEditorStore(state => state.helpOpen); const pendingExternalId = useEditorStore(state => state.pendingExternalId); @@ -24,6 +21,61 @@ export const EditorDialogs = memo(({ onDownload, onLoadFromStore, language = "en const setShareDialogOpen = useEditorStore(state => state.setShareDialogOpen); const setLoadExternalDialogOpen = useEditorStore(state => state.setLoadExternalDialogOpen); const setPendingExternalId = useEditorStore(state => state.setPendingExternalId); + const getRoadmapData = useEditorStore(state => state.getRoadmapData); + const loadRoadmapData = useEditorStore(state => state.loadRoadmapData); + + const language = settings?.language || defaultLanguage; + const t = getTranslations(language); + + const onDownload = () => { + const roadmapData = getRoadmapData(); + const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(roadmapData, null, 2)); + const downloadAnchorNode = document.createElement('a'); + downloadAnchorNode.setAttribute("href", dataStr); + downloadAnchorNode.setAttribute("download", "learningmap.json"); + document.body.appendChild(downloadAnchorNode); + downloadAnchorNode.click(); + downloadAnchorNode.remove(); + }; + + const onLoadFromStore = async (id: string) => { + try { + const response = await fetch(`${jsonStore}/api/json/${id}`); + if (!response.ok) throw new Error("Failed to load from JSON store"); + const data = await response.json(); + loadRoadmapData(data); + setLoadExternalDialogOpen(false); + setPendingExternalId(null); + } catch (error) { + console.error("Failed to load from JSON store", error); + } + }; + + const keyboardShortcuts = [ + { action: t.shortcuts.undo, shortcut: "Ctrl+Z" }, + { action: t.shortcuts.redo, shortcut: "Ctrl+Y or Ctrl+Shift+Z" }, + { action: t.shortcuts.addTaskNode, shortcut: "Ctrl+1" }, + { action: t.shortcuts.addTopicNode, shortcut: "Ctrl+2" }, + { action: t.shortcuts.addImageNode, shortcut: "Ctrl+3" }, + { action: t.shortcuts.addTextNode, shortcut: "Ctrl+4" }, + { action: t.shortcuts.deleteNodeEdge, shortcut: "Delete" }, + { action: t.shortcuts.togglePreviewMode, shortcut: "Ctrl+P" }, + { action: t.shortcuts.toggleDebugMode, shortcut: "Ctrl+D" }, + { action: t.shortcuts.selectMultipleNodes, shortcut: "Ctrl+Click or Shift+Drag" }, + { action: t.shortcuts.selectAllNodes, shortcut: "Ctrl+A" }, + { action: t.shortcuts.showHelp, shortcut: "Ctrl+? or Help Button" }, + { action: t.shortcuts.save, shortcut: "Ctrl+S" }, + { action: t.shortcuts.zoomIn, shortcut: "Ctrl++" }, + { action: t.shortcuts.zoomOut, shortcut: "Ctrl+-" }, + { action: t.shortcuts.resetZoom, shortcut: "Ctrl+0" }, + { action: t.shortcuts.resetMap, shortcut: "Ctrl+Delete" }, + { action: t.shortcuts.fitView, shortcut: "Shift+!" }, + { action: t.shortcuts.zoomToSelection, shortcut: "Shift+@" }, + { action: t.shortcuts.toggleGrid, shortcut: "Ctrl+'" }, + { action: t.shortcuts.cut, shortcut: "Ctrl+X" }, + { action: t.shortcuts.copy, shortcut: "Ctrl+C" }, + { action: t.shortcuts.paste, shortcut: "Ctrl+V" }, + ]; return ( <> @@ -60,10 +112,7 @@ export const EditorDialogs = memo(({ onDownload, onLoadFromStore, language = "en - setShareDialogOpen(false)} - language={language} - /> + { setLoadExternalDialogOpen(false); @@ -75,7 +124,6 @@ export const EditorDialogs = memo(({ onDownload, onLoadFromStore, language = "en onLoadFromStore(pendingExternalId); } }} - language={language} /> ); diff --git a/packages/learningmap/src/EditorDrawer.tsx b/packages/learningmap/src/EditorDrawer.tsx index 2d190bb..e65a6e9 100644 --- a/packages/learningmap/src/EditorDrawer.tsx +++ b/packages/learningmap/src/EditorDrawer.tsx @@ -10,25 +10,27 @@ import { getTranslations } from "./translations"; import { useEditorStore } from "./editorStore"; interface EditorDrawerProps { - isOpen: boolean; - onClose: () => void; - onUpdate: (node: Node) => void; - onDelete: () => void; - language?: string; + defaultLanguage?: string; } export const EditorDrawer: React.FC = ({ - isOpen, - onClose, - onUpdate, - onDelete, - language = "en", + defaultLanguage = "en", }) => { - const t = getTranslations(language); - // Get node and all nodes from store const selectedNodeId = useEditorStore(state => state.selectedNodeId); const nodes = useEditorStore(state => state.nodes); + const isOpen = useEditorStore(state => state.drawerOpen); + const settings = useEditorStore(state => state.settings); + + // Get actions from store + const setDrawerOpen = useEditorStore(state => state.setDrawerOpen); + const setSelectedNodeId = useEditorStore(state => state.setSelectedNodeId); + const updateNode = useEditorStore(state => state.updateNode); + const deleteNode = useEditorStore(state => state.deleteNode); + + const language = settings?.language || defaultLanguage; + const t = getTranslations(language); + const node = nodes.find(n => n.id === selectedNodeId) || null; const [localNode, setLocalNode] = useState | null>(node); @@ -37,6 +39,22 @@ export const EditorDrawer: React.FC = ({ setLocalNode(node); }, [node]); + const onClose = () => { + setDrawerOpen(false); + setSelectedNodeId(null); + }; + + const onUpdate = (updatedNode: Node) => { + updateNode(updatedNode.id, updatedNode); + }; + + const onDelete = () => { + if (node && confirm(t.resetMapWarning)) { + deleteNode(node.id); + onClose(); + } + }; + if (!isOpen || !node || !localNode) return null; // Filter out the current node from selectable options diff --git a/packages/learningmap/src/EditorToolbar.tsx b/packages/learningmap/src/EditorToolbar.tsx index b8cfa39..fc76168 100644 --- a/packages/learningmap/src/EditorToolbar.tsx +++ b/packages/learningmap/src/EditorToolbar.tsx @@ -5,29 +5,18 @@ import '@szhsin/react-menu/dist/transitions/zoom.css'; import { Plus, Bug, Settings, Eye, Menu as MenuI, FolderOpen, Download, ImageDown, ExternalLink, Share2, RotateCcw } from "lucide-react"; import { getTranslations } from "./translations"; import { useEditorStore } from "./editorStore"; +import { Node } from "@xyflow/react"; +import { NodeData } from "./types"; interface EditorToolbarProps { - onAddNewNode: (type: "task" | "topic" | "image" | "text") => void; - onOpenSettingsDrawer: () => void; - onDownlad: () => void; - onOpen: () => void; - onShare: () => void; - onReset: () => void; - language?: string; + defaultLanguage?: string; } export const EditorToolbar: React.FC = ({ - onAddNewNode, - onOpenSettingsDrawer, - onDownlad, - onOpen, - onShare, - onReset, - language = "en", + defaultLanguage = "en", }) => { - const t = getTranslations(language); - // Get state directly from store + const settings = useEditorStore(state => state.settings); const debugMode = useEditorStore(state => state.debugMode); const previewMode = useEditorStore(state => state.previewMode); const showCompletionNeeds = useEditorStore(state => state.showCompletionNeeds); @@ -40,12 +29,83 @@ export const EditorToolbar: React.FC = ({ const setShowCompletionNeeds = useEditorStore(state => state.setShowCompletionNeeds); const setShowCompletionOptional = useEditorStore(state => state.setShowCompletionOptional); const setShowUnlockAfter = useEditorStore(state => state.setShowUnlockAfter); + const addNode = useEditorStore(state => state.addNode); + const setSettingsDrawerOpen = useEditorStore(state => state.setSettingsDrawerOpen); + const getRoadmapData = useEditorStore(state => state.getRoadmapData); + const setShareDialogOpen = useEditorStore(state => state.setShareDialogOpen); + const setLoadExternalDialogOpen = useEditorStore(state => state.setLoadExternalDialogOpen); + const setNodes = useEditorStore(state => state.setNodes); + const setEdges = useEditorStore(state => state.setEdges); + const setSettings = useEditorStore(state => state.setSettings); + + const language = settings?.language || defaultLanguage; + const t = getTranslations(language); const onToggleDebugMode = () => setDebugMode(!debugMode); const onTogglePreviewMode = () => setPreviewMode(!previewMode); const onSetShowCompletionNeeds = (checked: boolean) => setShowCompletionNeeds(checked); const onSetShowCompletionOptional = (checked: boolean) => setShowCompletionOptional(checked); const onSetShowUnlockAfter = (checked: boolean) => setShowUnlockAfter(checked); + + const onAddNewNode = (type: "task" | "topic" | "image" | "text") => { + const position = { x: Math.random() * 500, y: Math.random() * 500 }; + const newNode: Node = { + id: `node-${Date.now()}`, + type, + position, + data: { + label: type === "task" ? t.newTask : type === "topic" ? t.newTopic : type, + state: "unlocked", + }, + }; + addNode(newNode); + }; + + const onOpenSettingsDrawer = () => setSettingsDrawerOpen(true); + + const onDownload = () => { + const roadmapData = getRoadmapData(); + const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(roadmapData, null, 2)); + const downloadAnchorNode = document.createElement('a'); + downloadAnchorNode.setAttribute("href", dataStr); + downloadAnchorNode.setAttribute("download", "learningmap.json"); + document.body.appendChild(downloadAnchorNode); + downloadAnchorNode.click(); + downloadAnchorNode.remove(); + }; + + const onOpen = () => { + const input = document.createElement('input'); + input.type = 'file'; + input.accept = 'application/json'; + input.onchange = (e: any) => { + const file = e.target.files[0]; + if (file) { + const reader = new FileReader(); + reader.onload = (e: any) => { + try { + const data = JSON.parse(e.target.result); + useEditorStore.getState().loadRoadmapData(data); + } catch (error) { + console.error("Failed to parse JSON file", error); + } + }; + reader.readAsText(file); + } + }; + input.click(); + }; + + const onShare = () => setShareDialogOpen(true); + + const onReset = () => { + if (confirm(t.resetMapWarning)) { + // Reset all state + setNodes([]); + setEdges([]); + setSettings({}); + } + }; return (
@@ -77,7 +137,7 @@ export const EditorToolbar: React.FC = ({ {t.open} - + {t.download} diff --git a/packages/learningmap/src/KeyboardShortcuts.tsx b/packages/learningmap/src/KeyboardShortcuts.tsx index c3a562e..e797bc7 100644 --- a/packages/learningmap/src/KeyboardShortcuts.tsx +++ b/packages/learningmap/src/KeyboardShortcuts.tsx @@ -1,50 +1,150 @@ import { useEffect } from "react"; import { useReactFlow } from "@xyflow/react"; -import { useEditorStore } from "./editorStore"; +import { useEditorStore, useTemporalStore } from "./editorStore"; +import { Node } from "@xyflow/react"; +import { NodeData } from "./types"; +import { getTranslations } from "./translations"; interface KeyboardShortcutsProps { - onAddNode: (type: "task" | "topic" | "image" | "text") => void; - onDeleteSelected: () => void; - onSave: () => void; - onUndo: () => void; - onRedo: () => void; - onTogglePreview: () => void; - onToggleDebug: () => void; - onResetMap: () => void; - onCut: () => void; - onCopy: () => void; - onPaste: () => void; - onSelectAll: () => void; - onZoomIn: () => void; - onZoomOut: () => void; - onResetZoom: () => void; - onFitView: () => void; - onZoomToSelection: () => void; - onToggleGrid: () => void; + jsonStore?: string; } -export const KeyboardShortcuts = ({ - onAddNode, - onDeleteSelected, - onSave, - onUndo, - onRedo, - onTogglePreview, - onToggleDebug, - onResetMap, - onCut, - onCopy, - onPaste, - onSelectAll, - onZoomIn, - onZoomOut, - onResetZoom, - onFitView, - onZoomToSelection, - onToggleGrid, -}: KeyboardShortcutsProps) => { - const setHelpOpen = useEditorStore(state => state.setHelpOpen); +export const KeyboardShortcuts = ({ jsonStore = "https://json.openpatch.org" }: KeyboardShortcutsProps) => { + const { zoomIn, zoomOut, setCenter, fitView, screenToFlowPosition } = useReactFlow(); + + // Get store state const helpOpen = useEditorStore(state => state.helpOpen); + const selectedNodeIds = useEditorStore(state => state.selectedNodeIds); + const nodes = useEditorStore(state => state.nodes); + const lastMousePosition = useEditorStore(state => state.lastMousePosition); + const settings = useEditorStore(state => state.settings); + + // Get store actions + const setHelpOpen = useEditorStore(state => state.setHelpOpen); + const addNode = useEditorStore(state => state.addNode); + const getRoadmapData = useEditorStore(state => state.getRoadmapData); + const setPreviewMode = useEditorStore(state => state.setPreviewMode); + const setDebugMode = useEditorStore(state => state.setDebugMode); + const setClipboard = useEditorStore(state => state.setClipboard); + const clipboard = useEditorStore(state => state.clipboard); + const setNodes = useEditorStore(state => state.setNodes); + const setEdges = useEditorStore(state => state.setEdges); + const setSelectedNodeIds = useEditorStore(state => state.setSelectedNodeIds); + const showGrid = useEditorStore(state => state.showGrid); + const setShowGrid = useEditorStore(state => state.setShowGrid); + const deleteNode = useEditorStore(state => state.deleteNode); + + const language = settings?.language || "en"; + const t = getTranslations(language); + + // Temporal store for undo/redo + const { undo, redo } = useTemporalStore((state) => ({ + undo: state.undo, + redo: state.redo, + })); + + const onAddNode = (type: "task" | "topic" | "image" | "text") => { + const position = lastMousePosition || screenToFlowPosition({ x: window.innerWidth / 2, y: window.innerHeight / 2 }); + const newNode: Node = { + id: `node-${Date.now()}`, + type, + position, + data: { + label: type === "task" ? t.newTask : type === "topic" ? t.newTopic : type, + state: "unlocked", + }, + }; + addNode(newNode); + }; + + const onDeleteSelected = () => { + if (selectedNodeIds.length > 0) { + // Delete all selected nodes + selectedNodeIds.forEach(nodeId => { + deleteNode(nodeId); + }); + setSelectedNodeIds([]); + } + }; + + const onSave = () => { + const roadmapData = getRoadmapData(); + const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(roadmapData, null, 2)); + const downloadAnchorNode = document.createElement('a'); + downloadAnchorNode.setAttribute("href", dataStr); + downloadAnchorNode.setAttribute("download", "learningmap.json"); + document.body.appendChild(downloadAnchorNode); + downloadAnchorNode.click(); + downloadAnchorNode.remove(); + }; + + const onTogglePreview = () => { + const currentPreviewMode = useEditorStore.getState().previewMode; + setPreviewMode(!currentPreviewMode); + }; + + const onToggleDebug = () => { + const currentDebugMode = useEditorStore.getState().debugMode; + setDebugMode(!currentDebugMode); + }; + + const onResetMap = () => { + if (confirm(t.resetMapWarning)) { + setNodes([]); + setEdges([]); + } + }; + + const onCut = () => { + const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); + if (selectedNodes.length > 0) { + setClipboard({ nodes: selectedNodes, edges: [] }); + // Delete all selected nodes + selectedNodeIds.forEach(nodeId => { + deleteNode(nodeId); + }); + setSelectedNodeIds([]); + } + }; + + const onCopy = () => { + const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); + if (selectedNodes.length > 0) { + setClipboard({ nodes: selectedNodes, edges: [] }); + } + }; + + const onPaste = () => { + if (clipboard && clipboard.nodes.length > 0) { + const newNodes = clipboard.nodes.map(n => ({ + ...n, + id: `node-${Date.now()}-${Math.random()}`, + position: { x: n.position.x + 50, y: n.position.y + 50 }, + })); + setNodes([...nodes, ...newNodes]); + setSelectedNodeIds(newNodes.map(n => n.id)); + } + }; + + const onSelectAll = () => { + setSelectedNodeIds(nodes.map(n => n.id)); + }; + + const onZoomIn = () => zoomIn(); + const onZoomOut = () => zoomOut(); + const onResetZoom = () => setCenter(0, 0, { zoom: 1 }); + const onFitView = () => fitView(); + + const onZoomToSelection = () => { + if (selectedNodeIds.length > 0) { + const selectedNodes = nodes.filter(n => selectedNodeIds.includes(n.id)); + if (selectedNodes.length > 0) { + fitView({ nodes: selectedNodes, duration: 300 }); + } + } + }; + + const onToggleGrid = () => setShowGrid(!showGrid); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { @@ -66,10 +166,10 @@ export const KeyboardShortcuts = ({ onSave(); } else if (e.key === 'z' && !e.shiftKey) { e.preventDefault(); - onUndo(); + undo(); } else if ((e.key === 'y') || (e.key === 'z' && e.shiftKey)) { e.preventDefault(); - onRedo(); + redo(); } else if ((e.key === '?' || (e.shiftKey && e.key === '/'))) { e.preventDefault(); setHelpOpen(!helpOpen); @@ -125,7 +225,7 @@ export const KeyboardShortcuts = ({ return () => { window.removeEventListener("keydown", handleKeyDown); }; - }, [onAddNode, onDeleteSelected, onSave, onUndo, onRedo, helpOpen, setHelpOpen, onTogglePreview, onToggleDebug, + }, [onAddNode, onDeleteSelected, onSave, undo, redo, helpOpen, setHelpOpen, onTogglePreview, onToggleDebug, onZoomIn, onZoomOut, onResetZoom, onFitView, onZoomToSelection, onToggleGrid, onResetMap, onCut, onCopy, onPaste, onSelectAll]); diff --git a/packages/learningmap/src/LearningMapEditor.tsx b/packages/learningmap/src/LearningMapEditor.tsx index 2a387e1..624647f 100644 --- a/packages/learningmap/src/LearningMapEditor.tsx +++ b/packages/learningmap/src/LearningMapEditor.tsx @@ -34,7 +34,6 @@ export function LearningMapEditor({ }: LearningMapEditorProps) { const parsedRoadmap = parseRoadmapData(roadmapData || ""); - const { screenToFlowPosition } = useReactFlow(); // Only get minimal state needed in this component const nodes = useEditorStore(state => state.nodes); @@ -45,70 +44,9 @@ export function LearningMapEditor({ // Store actions const loadRoadmapData = useEditorStore(state => state.loadRoadmapData); const getRoadmapData = useEditorStore(state => state.getRoadmapData); - const setHelpOpen = useEditorStore(state => state.setHelpOpen); - const setSettings = useEditorStore(state => state.setSettings); // Use language from settings if available, otherwise use prop const effectiveLanguage = settings?.language || language; - const t = getTranslations(effectiveLanguage); - - // Use the custom hook for all editor actions - const { - handleNodeClick, - handleEdgeClick, - closeDrawer, - handleUpdateNode, - handleUpdateEdge, - handleDeleteEdge, - handleDeleteNode, - addNewNode, - togglePreviewMode, - toggleDebugMode, - handleDownload, - handleShare, - loadFromJsonStore, - handleOpen, - handleOpenSettingsDrawer, - handleCut, - handleCopy, - handlePaste, - handleZoomIn, - handleZoomOut, - handleResetZoom, - handleFitView, - handleZoomToSelection, - handleToggleGrid, - handleResetMap, - handleSelectAll, - handleDeleteSelected, - handleSave, - } = useEditorActions(t, screenToFlowPosition, jsonStore); - - const keyboardShortcuts = [ - { action: t.shortcuts.undo, shortcut: "Ctrl+Z" }, - { action: t.shortcuts.redo, shortcut: "Ctrl+Y or Ctrl+Shift+Z" }, - { action: t.shortcuts.addTaskNode, shortcut: "Ctrl+1" }, - { action: t.shortcuts.addTopicNode, shortcut: "Ctrl+2" }, - { action: t.shortcuts.addImageNode, shortcut: "Ctrl+3" }, - { action: t.shortcuts.addTextNode, shortcut: "Ctrl+4" }, - { action: t.shortcuts.deleteNodeEdge, shortcut: "Delete" }, - { action: t.shortcuts.togglePreviewMode, shortcut: "Ctrl+P" }, - { action: t.shortcuts.toggleDebugMode, shortcut: "Ctrl+D" }, - { action: t.shortcuts.selectMultipleNodes, shortcut: "Ctrl+Click or Shift+Drag" }, - { action: t.shortcuts.selectAllNodes, shortcut: "Ctrl+A" }, - { action: t.shortcuts.showHelp, shortcut: "Ctrl+? or Help Button" }, - { action: t.shortcuts.save, shortcut: "Ctrl+S" }, - { action: t.shortcuts.zoomIn, shortcut: "Ctrl++" }, - { action: t.shortcuts.zoomOut, shortcut: "Ctrl+-" }, - { action: t.shortcuts.resetZoom, shortcut: "Ctrl+0" }, - { action: t.shortcuts.resetMap, shortcut: "Ctrl+Delete" }, - { action: t.shortcuts.fitView, shortcut: "Shift+!" }, - { action: t.shortcuts.zoomToSelection, shortcut: "Shift+@" }, - { action: t.shortcuts.toggleGrid, shortcut: "Ctrl+'" }, - { action: t.shortcuts.cut, shortcut: "Ctrl+X" }, - { action: t.shortcuts.copy, shortcut: "Ctrl+C" }, - { action: t.shortcuts.paste, shortcut: "Ctrl+V" }, - ]; // Load roadmap data when prop changes useEffect(() => { @@ -129,84 +67,27 @@ export function LearningMapEditor({ {/* Keyboard shortcuts handler */} - {}} // Handled by EditorCanvas - onRedo={() => {}} // Handled by EditorCanvas - onTogglePreview={togglePreviewMode} - onToggleDebug={toggleDebugMode} - onResetMap={handleResetMap} - onCut={handleCut} - onCopy={handleCopy} - onPaste={handlePaste} - onSelectAll={handleSelectAll} - onZoomIn={handleZoomIn} - onZoomOut={handleZoomOut} - onResetZoom={handleResetZoom} - onFitView={handleFitView} - onZoomToSelection={handleZoomToSelection} - onToggleGrid={handleToggleGrid} - /> + {/* Toolbar */} - + {/* Preview or Edit mode */} {previewMode && } {!previewMode && <> {/* Welcome message when empty */} - {nodes.length === 0 && edges.length === 0 && addNewNode("topic")} - onShowHelp={() => setHelpOpen(true)} - language={effectiveLanguage} - />} + {nodes.length === 0 && edges.length === 0 && } {/* Main canvas */} - + {/* Drawers */} - - - + + + {/* Dialogs */} - + } ); diff --git a/packages/learningmap/src/LoadExternalDialog.tsx b/packages/learningmap/src/LoadExternalDialog.tsx index b754184..8930077 100644 --- a/packages/learningmap/src/LoadExternalDialog.tsx +++ b/packages/learningmap/src/LoadExternalDialog.tsx @@ -7,19 +7,19 @@ interface LoadExternalDialogProps { onClose: () => void; onDownloadCurrent: () => void; onReplace: () => void; - language?: string; } export function LoadExternalDialog({ onClose, onDownloadCurrent, onReplace, - language = "en", }: LoadExternalDialogProps) { - const t = getTranslations(language); - // Get state from store const open = useEditorStore(state => state.loadExternalDialogOpen); + const settings = useEditorStore(state => state.settings); + + const language = settings?.language || "en"; + const t = getTranslations(language); if (!open) return null; diff --git a/packages/learningmap/src/MultiNodePanel.tsx b/packages/learningmap/src/MultiNodePanel.tsx index 86d6dae..0c0f961 100644 --- a/packages/learningmap/src/MultiNodePanel.tsx +++ b/packages/learningmap/src/MultiNodePanel.tsx @@ -4,14 +4,12 @@ import { FC } from "react"; import { AlignCenterVertical, AlignCenterHorizontal, AlignEndHorizontal, AlignEndVertical, AlignStartVertical, AlignStartHorizontal, RulerDimensionLine, AlignVerticalDistributeCenter, AlignHorizontalDistributeCenter } from "lucide-react"; import { useEditorStore } from "./editorStore"; -interface Props { - onUpdate: (nodes: Node[]) => void; -} - -export const MultiNodePanel: FC = ({ onUpdate }) => { +export const MultiNodePanel: FC = () => { // Get selected nodes from store const selectedNodeIds = useEditorStore(state => state.selectedNodeIds); const allNodes = useEditorStore(state => state.nodes); + const updateNodes = useEditorStore(state => state.updateNodes); + const nodes = allNodes.filter(n => selectedNodeIds.includes(n.id)); if (nodes.length < 2) return null; @@ -23,7 +21,7 @@ export const MultiNodePanel: FC = ({ onUpdate }) => { ...n, position: { ...n.position, x: minX } })); - onUpdate(updatedNodes); + updateNodes(updatedNodes); }; const alignCenterVertical = () => { @@ -33,7 +31,7 @@ export const MultiNodePanel: FC = ({ onUpdate }) => { ...n, position: { ...n.position, x: avgX - (n.width || n.measured.width) / 2 } })); - onUpdate(updatedNodes); + updateNodes(updatedNodes); }; const alignRightVertical = () => { @@ -43,7 +41,7 @@ export const MultiNodePanel: FC = ({ onUpdate }) => { ...n, position: { ...n.position, x: maxX - (n.width || n.measured.width) } })); - onUpdate(updatedNodes); + updateNodes(updatedNodes); }; const alignLeft = () => { @@ -53,7 +51,7 @@ export const MultiNodePanel: FC = ({ onUpdate }) => { ...n, position: { ...n.position, y: minY } })); - onUpdate(updatedNodes); + updateNodes(updatedNodes); }; const alignCenter = () => { @@ -63,7 +61,7 @@ export const MultiNodePanel: FC = ({ onUpdate }) => { ...n, position: { ...n.position, y: avgY - (n.height || n.measured.height) / 2 } })); - onUpdate(updatedNodes); + updateNodes(updatedNodes); }; const alignRight = () => { @@ -73,7 +71,7 @@ export const MultiNodePanel: FC = ({ onUpdate }) => { ...n, position: { ...n.position, y: maxY - (n.height || n.measured.height) } })); - onUpdate(updatedNodes); + updateNodes(updatedNodes); }; const distributeVertical = () => { @@ -94,7 +92,7 @@ export const MultiNodePanel: FC = ({ onUpdate }) => { currentY += (n.height || n.measured.height) + gap; return updatedNode; }); - onUpdate(updatedNodes); + updateNodes(updatedNodes); }; const distributeHorizontal = () => { @@ -114,7 +112,7 @@ export const MultiNodePanel: FC = ({ onUpdate }) => { currentX += (n.width || n.measured.width) + gap; return updatedNode; }); - onUpdate(updatedNodes); + updateNodes(updatedNodes); }; const sameWidth = () => { @@ -124,7 +122,7 @@ export const MultiNodePanel: FC = ({ onUpdate }) => { ...n, width: maxWidth })); - onUpdate(updatedNodes); + updateNodes(updatedNodes); }; const sameHeight = () => { @@ -134,7 +132,7 @@ export const MultiNodePanel: FC = ({ onUpdate }) => { ...n, height: maxHeight })); - onUpdate(updatedNodes); + updateNodes(updatedNodes); }; return diff --git a/packages/learningmap/src/SettingsDrawer.tsx b/packages/learningmap/src/SettingsDrawer.tsx index 15a5cf1..d292cd6 100644 --- a/packages/learningmap/src/SettingsDrawer.tsx +++ b/packages/learningmap/src/SettingsDrawer.tsx @@ -7,22 +7,23 @@ import { useReactFlow } from "@xyflow/react"; import { useEditorStore } from "./editorStore"; interface SettingsDrawerProps { - onClose: () => void; - onUpdate: (s: Settings) => void; - language?: string; + defaultLanguage?: string; } export const SettingsDrawer: React.FC = ({ - onClose, - onUpdate, - language = "en", + defaultLanguage = "en", }) => { - const t = getTranslations(language); - // Get state from store const isOpen = useEditorStore(state => state.settingsDrawerOpen); const settings = useEditorStore(state => state.settings); + // Get actions from store + const setSettingsDrawerOpen = useEditorStore(state => state.setSettingsDrawerOpen); + const setSettings = useEditorStore(state => state.setSettings); + + const language = settings?.language || defaultLanguage; + const t = getTranslations(language); + const [localSettings, setLocalSettings] = useState(settings); const { getViewport } = useReactFlow(); @@ -30,6 +31,12 @@ export const SettingsDrawer: React.FC = ({ setLocalSettings(settings); }, [settings]); + const onClose = () => setSettingsDrawerOpen(false); + + const onUpdate = (s: Settings) => { + setSettings(s); + }; + if (!isOpen) return null; const handleSave = () => { diff --git a/packages/learningmap/src/ShareDialog.tsx b/packages/learningmap/src/ShareDialog.tsx index 4062ec6..c006775 100644 --- a/packages/learningmap/src/ShareDialog.tsx +++ b/packages/learningmap/src/ShareDialog.tsx @@ -3,18 +3,19 @@ import { X, Link2, Check } from "lucide-react"; import { getTranslations } from "./translations"; import { useEditorStore } from "./editorStore"; -interface ShareDialogProps { - onClose: () => void; - language?: string; -} - -export function ShareDialog({ onClose, language = "en" }: ShareDialogProps) { - const t = getTranslations(language); +export function ShareDialog() { const [copied, setCopied] = useState(false); // Get state from store const open = useEditorStore(state => state.shareDialogOpen); const shareLink = useEditorStore(state => state.shareLink); + const settings = useEditorStore(state => state.settings); + const setShareDialogOpen = useEditorStore(state => state.setShareDialogOpen); + + const language = settings?.language || "en"; + const t = getTranslations(language); + + const onClose = () => setShareDialogOpen(false); if (!open) return null; diff --git a/packages/learningmap/src/WelcomeMessage.tsx b/packages/learningmap/src/WelcomeMessage.tsx index 35fc8a6..8beb4f9 100644 --- a/packages/learningmap/src/WelcomeMessage.tsx +++ b/packages/learningmap/src/WelcomeMessage.tsx @@ -1,23 +1,65 @@ import React from "react"; import { FolderOpen, Plus, Info } from "lucide-react"; import { getTranslations } from "./translations"; +import { useEditorStore } from "./editorStore"; +import { Node } from "@xyflow/react"; +import { NodeData } from "./types"; import logo from "./logo.svg"; interface WelcomeMessageProps { - onOpenFile: () => void; - onAddTopic: () => void; - onShowHelp: () => void; - language?: string; + defaultLanguage?: string; } export const WelcomeMessage: React.FC = ({ - onOpenFile, - onAddTopic, - onShowHelp, - language = "en", + defaultLanguage = "en", }) => { + // Get state and actions from store + const settings = useEditorStore(state => state.settings); + const addNode = useEditorStore(state => state.addNode); + const setHelpOpen = useEditorStore(state => state.setHelpOpen); + const loadRoadmapData = useEditorStore(state => state.loadRoadmapData); + + const language = settings?.language || defaultLanguage; const t = getTranslations(language); + const onOpenFile = () => { + const input = document.createElement('input'); + input.type = 'file'; + input.accept = 'application/json'; + input.onchange = (e: any) => { + const file = e.target.files[0]; + if (file) { + const reader = new FileReader(); + reader.onload = (e: any) => { + try { + const data = JSON.parse(e.target.result); + loadRoadmapData(data); + } catch (error) { + console.error("Failed to parse JSON file", error); + } + }; + reader.readAsText(file); + } + }; + input.click(); + }; + + const onAddTopic = () => { + const position = { x: window.innerWidth / 2, y: window.innerHeight / 2 }; + const newNode: Node = { + id: `node-${Date.now()}`, + type: "topic", + position, + data: { + label: t.newTopic, + state: "unlocked", + }, + }; + addNode(newNode); + }; + + const onShowHelp = () => setHelpOpen(true); + return (
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fcef677..8b64214 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '9.0' +lockfileVersion: '6.0' settings: autoInstallPeers: true @@ -61,10 +61,10 @@ importers: dependencies: '@szhsin/react-menu': specifier: ^4.5.0 - version: 4.5.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 4.5.0(react-dom@19.2.0)(react@19.2.0) '@xyflow/react': specifier: ^12.8.6 - version: 12.8.6(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 12.8.6(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) elkjs: specifier: ^0.11.0 version: 0.11.0 @@ -85,10 +85,10 @@ importers: version: 2.8.1 zundo: specifier: ^2.3.0 - version: 2.3.0(zustand@5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0))) + version: 2.3.0(zustand@5.0.8) zustand: specifier: ^5.0.8 - version: 5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) + version: 5.0.8(@types/react@19.2.2)(react@19.2.0) devDependencies: '@types/react': specifier: ^19.2.2 @@ -98,7 +98,7 @@ importers: version: 19.2.1(@types/react@19.2.2) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/node@24.7.2)(terser@5.44.0) + version: 3.2.4(@types/node@24.7.2) packages/web-component: dependencies: @@ -107,7 +107,7 @@ importers: version: link:../learningmap '@r2wc/react-to-web-component': specifier: ^2.1.0 - version: 2.1.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.1.0(react-dom@19.2.0)(react@19.2.0) react: specifier: ^19.2.0 version: 19.2.0 @@ -120,7 +120,7 @@ importers: devDependencies: '@rollup/plugin-typescript': specifier: ^12.1.4 - version: 12.1.4(rollup@4.52.4)(tslib@2.8.1)(typescript@5.9.3) + version: 12.1.4(tslib@2.8.1)(typescript@5.9.3) '@types/react': specifier: ^19.2.2 version: 19.2.2 @@ -129,10 +129,10 @@ importers: version: 19.2.1(@types/react@19.2.2) '@vitejs/plugin-react': specifier: ^5.0.4 - version: 5.0.4(vite@7.1.9(@types/node@24.7.2)(terser@5.44.0)) + version: 5.0.4(vite@7.1.9) vite: specifier: ^7.1.9 - version: 7.1.9(@types/node@24.7.2)(terser@5.44.0) + version: 7.1.9(@types/node@24.7.2) platforms/web: dependencies: @@ -160,7 +160,7 @@ importers: version: 19.2.1(@types/react@19.2.2) '@vitejs/plugin-react': specifier: ^5.0.4 - version: 5.0.4(vite@7.1.9(@types/node@24.7.2)(terser@5.44.0)) + version: 5.0.4(vite@7.1.9) eslint: specifier: ^9.36.0 version: 9.37.0 @@ -181,376 +181,735 @@ importers: version: 8.46.0(eslint@9.37.0)(typescript@5.9.3) vite: specifier: ^7.1.9 - version: 7.1.9(@types/node@24.7.2)(terser@5.44.0) + version: 7.1.9(@types/node@24.7.2) packages: - '@babel/code-frame@7.27.1': + /@babel/code-frame@7.27.1: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + dev: true - '@babel/compat-data@7.28.4': + /@babel/compat-data@7.28.4: resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} engines: {node: '>=6.9.0'} + dev: true - '@babel/core@7.28.4': + /@babel/core@7.28.4: resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.4 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true - '@babel/generator@7.28.3': + /@babel/generator@7.28.3: resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + dev: true - '@babel/helper-compilation-targets@7.27.2': + /@babel/helper-compilation-targets@7.27.2: resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.28.4 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.26.3 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true - '@babel/helper-globals@7.28.0': + /@babel/helper-globals@7.28.0: resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} + dev: true - '@babel/helper-module-imports@7.27.1': + /@babel/helper-module-imports@7.27.1: resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + transitivePeerDependencies: + - supports-color + dev: true - '@babel/helper-module-transforms@7.28.3': + /@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4): resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.4 + transitivePeerDependencies: + - supports-color + dev: true - '@babel/helper-plugin-utils@7.27.1': + /@babel/helper-plugin-utils@7.27.1: resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} engines: {node: '>=6.9.0'} + dev: true - '@babel/helper-string-parser@7.27.1': + /@babel/helper-string-parser@7.27.1: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + dev: true - '@babel/helper-validator-identifier@7.27.1': + /@babel/helper-validator-identifier@7.27.1: resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + dev: true - '@babel/helper-validator-option@7.27.1': + /@babel/helper-validator-option@7.27.1: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} + dev: true - '@babel/helpers@7.28.4': + /@babel/helpers@7.28.4: resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.4 + dev: true - '@babel/parser@7.28.4': + /@babel/parser@7.28.4: resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} engines: {node: '>=6.0.0'} hasBin: true + dependencies: + '@babel/types': 7.28.4 + dev: true - '@babel/plugin-transform-react-jsx-self@7.27.1': + /@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4): resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + dev: true - '@babel/plugin-transform-react-jsx-source@7.27.1': + /@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4): resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + dev: true - '@babel/runtime@7.28.4': + /@babel/runtime@7.28.4: resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} + dev: true - '@babel/template@7.27.2': + /@babel/template@7.27.2: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + dev: true - '@babel/traverse@7.28.4': + /@babel/traverse@7.28.4: resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.4 + '@babel/template': 7.27.2 + '@babel/types': 7.28.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + dev: true - '@babel/types@7.28.4': + /@babel/types@7.28.4: resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + dev: true - '@changesets/apply-release-plan@7.0.13': + /@changesets/apply-release-plan@7.0.13: resolution: {integrity: sha512-BIW7bofD2yAWoE8H4V40FikC+1nNFEKBisMECccS16W1rt6qqhNTBDmIw5HaqmMgtLNz9e7oiALiEUuKrQ4oHg==} + dependencies: + '@changesets/config': 3.1.1 + '@changesets/get-version-range-type': 0.4.0 + '@changesets/git': 3.0.4 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + detect-indent: 6.1.0 + fs-extra: 7.0.1 + lodash.startcase: 4.4.0 + outdent: 0.5.0 + prettier: 2.8.8 + resolve-from: 5.0.0 + semver: 7.7.3 + dev: true - '@changesets/assemble-release-plan@6.0.9': + /@changesets/assemble-release-plan@6.0.9: resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==} + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + semver: 7.7.3 + dev: true - '@changesets/changelog-git@0.2.1': + /@changesets/changelog-git@0.2.1: resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} + dependencies: + '@changesets/types': 6.1.0 + dev: true - '@changesets/changelog-github@0.5.1': + /@changesets/changelog-github@0.5.1: resolution: {integrity: sha512-BVuHtF+hrhUScSoHnJwTELB4/INQxVFc+P/Qdt20BLiBFIHFJDDUaGsZw+8fQeJTRP5hJZrzpt3oZWh0G19rAQ==} + dependencies: + '@changesets/get-github-info': 0.6.0 + '@changesets/types': 6.1.0 + dotenv: 8.6.0 + transitivePeerDependencies: + - encoding + dev: true - '@changesets/cli@2.29.7': + /@changesets/cli@2.29.7(@types/node@24.7.2): resolution: {integrity: sha512-R7RqWoaksyyKXbKXBTbT4REdy22yH81mcFK6sWtqSanxUCbUi9Uf+6aqxZtDQouIqPdem2W56CdxXgsxdq7FLQ==} hasBin: true + dependencies: + '@changesets/apply-release-plan': 7.0.13 + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/changelog-git': 0.2.1 + '@changesets/config': 3.1.1 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/get-release-plan': 4.0.13 + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.5 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@changesets/write': 0.4.0 + '@inquirer/external-editor': 1.0.2(@types/node@24.7.2) + '@manypkg/get-packages': 1.1.3 + ansi-colors: 4.1.3 + ci-info: 3.9.0 + enquirer: 2.4.1 + fs-extra: 7.0.1 + mri: 1.2.0 + p-limit: 2.3.0 + package-manager-detector: 0.2.11 + picocolors: 1.1.1 + resolve-from: 5.0.0 + semver: 7.7.3 + spawndamnit: 3.0.1 + term-size: 2.2.1 + transitivePeerDependencies: + - '@types/node' + dev: true - '@changesets/config@3.1.1': + /@changesets/config@3.1.1: resolution: {integrity: sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==} + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/logger': 0.1.1 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + micromatch: 4.0.8 + dev: true - '@changesets/errors@0.2.0': + /@changesets/errors@0.2.0: resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} + dependencies: + extendable-error: 0.1.7 + dev: true - '@changesets/get-dependents-graph@2.1.3': + /@changesets/get-dependents-graph@2.1.3: resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + picocolors: 1.1.1 + semver: 7.7.3 + dev: true - '@changesets/get-github-info@0.6.0': + /@changesets/get-github-info@0.6.0: resolution: {integrity: sha512-v/TSnFVXI8vzX9/w3DU2Ol+UlTZcu3m0kXTjTT4KlAdwSvwutcByYwyYn9hwerPWfPkT2JfpoX0KgvCEi8Q/SA==} + dependencies: + dataloader: 1.4.0 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + dev: true - '@changesets/get-release-plan@4.0.13': + /@changesets/get-release-plan@4.0.13: resolution: {integrity: sha512-DWG1pus72FcNeXkM12tx+xtExyH/c9I1z+2aXlObH3i9YA7+WZEVaiHzHl03thpvAgWTRaH64MpfHxozfF7Dvg==} + dependencies: + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/config': 3.1.1 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.5 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + dev: true - '@changesets/get-version-range-type@0.4.0': + /@changesets/get-version-range-type@0.4.0: resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} + dev: true - '@changesets/git@3.0.4': + /@changesets/git@3.0.4: resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} + dependencies: + '@changesets/errors': 0.2.0 + '@manypkg/get-packages': 1.1.3 + is-subdir: 1.2.0 + micromatch: 4.0.8 + spawndamnit: 3.0.1 + dev: true - '@changesets/logger@0.1.1': + /@changesets/logger@0.1.1: resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} + dependencies: + picocolors: 1.1.1 + dev: true - '@changesets/parse@0.4.1': + /@changesets/parse@0.4.1: resolution: {integrity: sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==} + dependencies: + '@changesets/types': 6.1.0 + js-yaml: 3.14.1 + dev: true - '@changesets/pre@2.0.2': + /@changesets/pre@2.0.2: resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + dev: true - '@changesets/read@0.6.5': + /@changesets/read@0.6.5: resolution: {integrity: sha512-UPzNGhsSjHD3Veb0xO/MwvasGe8eMyNrR/sT9gR8Q3DhOQZirgKhhXv/8hVsI0QpPjR004Z9iFxoJU6in3uGMg==} + dependencies: + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/parse': 0.4.1 + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + p-filter: 2.1.0 + picocolors: 1.1.1 + dev: true - '@changesets/should-skip-package@0.1.2': + /@changesets/should-skip-package@0.1.2: resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + dev: true - '@changesets/types@4.1.0': + /@changesets/types@4.1.0: resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} + dev: true - '@changesets/types@6.1.0': + /@changesets/types@6.1.0: resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} + dev: true - '@changesets/write@0.4.0': + /@changesets/write@0.4.0: resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + dependencies: + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + human-id: 4.1.2 + prettier: 2.8.8 + dev: true - '@cspotcode/source-map-support@0.8.1': + /@cspotcode/source-map-support@0.8.1: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + dev: true - '@epic-web/invariant@1.0.0': + /@epic-web/invariant@1.0.0: resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} + dev: true - '@esbuild/aix-ppc64@0.25.10': + /@esbuild/aix-ppc64@0.25.10: resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-arm64@0.25.10': + /@esbuild/android-arm64@0.25.10: resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-arm@0.25.10': + /@esbuild/android-arm@0.25.10: resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} engines: {node: '>=18'} cpu: [arm] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-x64@0.25.10': + /@esbuild/android-x64@0.25.10: resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} engines: {node: '>=18'} cpu: [x64] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/darwin-arm64@0.25.10': + /@esbuild/darwin-arm64@0.25.10: resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@esbuild/darwin-x64@0.25.10': + /@esbuild/darwin-x64@0.25.10: resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@esbuild/freebsd-arm64@0.25.10': + /@esbuild/freebsd-arm64@0.25.10: resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/freebsd-x64@0.25.10': + /@esbuild/freebsd-x64@0.25.10: resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-arm64@0.25.10': + /@esbuild/linux-arm64@0.25.10: resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-arm@0.25.10': + /@esbuild/linux-arm@0.25.10: resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} engines: {node: '>=18'} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-ia32@0.25.10': + /@esbuild/linux-ia32@0.25.10: resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-loong64@0.25.10': + /@esbuild/linux-loong64@0.25.10: resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-mips64el@0.25.10': + /@esbuild/linux-mips64el@0.25.10: resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-ppc64@0.25.10': + /@esbuild/linux-ppc64@0.25.10: resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-riscv64@0.25.10': + /@esbuild/linux-riscv64@0.25.10: resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-s390x@0.25.10': + /@esbuild/linux-s390x@0.25.10: resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-x64@0.25.10': + /@esbuild/linux-x64@0.25.10: resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/netbsd-arm64@0.25.10': + /@esbuild/netbsd-arm64@0.25.10: resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/netbsd-x64@0.25.10': + /@esbuild/netbsd-x64@0.25.10: resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/openbsd-arm64@0.25.10': + /@esbuild/openbsd-arm64@0.25.10: resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/openbsd-x64@0.25.10': + /@esbuild/openbsd-x64@0.25.10: resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/openharmony-arm64@0.25.10': + /@esbuild/openharmony-arm64@0.25.10: resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + requiresBuild: true + dev: true + optional: true - '@esbuild/sunos-x64@0.25.10': + /@esbuild/sunos-x64@0.25.10: resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-arm64@0.25.10': + /@esbuild/win32-arm64@0.25.10: resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-ia32@0.25.10': + /@esbuild/win32-ia32@0.25.10: resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-x64@0.25.10': + /@esbuild/win32-x64@0.25.10: resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} engines: {node: '>=18'} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@eslint-community/eslint-utils@4.9.0': + /@eslint-community/eslint-utils@4.9.0(eslint@9.37.0): resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 9.37.0 + eslint-visitor-keys: 3.4.3 + dev: true - '@eslint-community/regexpp@4.12.1': + /@eslint-community/regexpp@4.12.1: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true - '@eslint/config-array@0.21.0': + /@eslint/config-array@0.21.0: resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true - '@eslint/config-helpers@0.4.0': + /@eslint/config-helpers@0.4.0: resolution: {integrity: sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/core': 0.16.0 + dev: true - '@eslint/core@0.16.0': + /@eslint/core@0.16.0: resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@types/json-schema': 7.0.15 + dev: true - '@eslint/eslintrc@3.3.1': + /@eslint/eslintrc@3.3.1: resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true - '@eslint/js@9.37.0': + /@eslint/js@9.37.0: resolution: {integrity: sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true - '@eslint/object-schema@2.1.6': + /@eslint/object-schema@2.1.6: resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true - '@eslint/plugin-kit@0.4.0': + /@eslint/plugin-kit@0.4.0: resolution: {integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/core': 0.16.0 + levn: 0.4.1 + dev: true - '@humanfs/core@0.19.1': + /@humanfs/core@0.19.1: resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} + dev: true - '@humanfs/node@0.16.7': + /@humanfs/node@0.16.7: resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} engines: {node: '>=18.18.0'} + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + dev: true - '@humanwhocodes/module-importer@1.0.1': + /@humanwhocodes/module-importer@1.0.1: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} + dev: true - '@humanwhocodes/retry@0.4.3': + /@humanwhocodes/retry@0.4.3: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + dev: true - '@inquirer/external-editor@1.0.2': + /@inquirer/external-editor@1.0.2(@types/node@24.7.2): resolution: {integrity: sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==} engines: {node: '>=18'} peerDependencies: @@ -558,76 +917,146 @@ packages: peerDependenciesMeta: '@types/node': optional: true + dependencies: + '@types/node': 24.7.2 + chardet: 2.1.0 + iconv-lite: 0.7.0 + dev: true - '@isaacs/balanced-match@4.0.1': + /@isaacs/balanced-match@4.0.1: resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} + dev: true - '@isaacs/brace-expansion@5.0.0': + /@isaacs/brace-expansion@5.0.0: resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} engines: {node: 20 || >=22} + dependencies: + '@isaacs/balanced-match': 4.0.1 + dev: true - '@isaacs/cliui@8.0.2': + /@isaacs/cliui@8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.2 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: true - '@jridgewell/gen-mapping@0.3.13': + /@jridgewell/gen-mapping@0.3.13: resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + dev: true - '@jridgewell/remapping@2.3.5': + /@jridgewell/remapping@2.3.5: resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + dev: true - '@jridgewell/resolve-uri@3.1.2': + /@jridgewell/resolve-uri@3.1.2: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + dev: true - '@jridgewell/source-map@0.3.11': + /@jridgewell/source-map@0.3.11: resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + dev: true - '@jridgewell/sourcemap-codec@1.5.5': + /@jridgewell/sourcemap-codec@1.5.5: resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + dev: true - '@jridgewell/trace-mapping@0.3.31': + /@jridgewell/trace-mapping@0.3.31: resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + dev: true - '@jridgewell/trace-mapping@0.3.9': + /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + dev: true - '@manypkg/find-root@1.1.0': + /@manypkg/find-root@1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} + dependencies: + '@babel/runtime': 7.28.4 + '@types/node': 12.20.55 + find-up: 4.1.0 + fs-extra: 8.1.0 + dev: true - '@manypkg/get-packages@1.1.3': + /@manypkg/get-packages@1.1.3: resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + dependencies: + '@babel/runtime': 7.28.4 + '@changesets/types': 4.1.0 + '@manypkg/find-root': 1.1.0 + fs-extra: 8.1.0 + globby: 11.1.0 + read-yaml-file: 1.1.0 + dev: true - '@nodelib/fs.scandir@2.1.5': + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true - '@nodelib/fs.stat@2.0.5': + /@nodelib/fs.stat@2.0.5: resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} + dev: true - '@nodelib/fs.walk@1.2.8': + /@nodelib/fs.walk@1.2.8: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + dev: true - '@pkgr/core@0.2.9': + /@pkgr/core@0.2.9: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dev: true - '@r2wc/core@1.3.0': + /@r2wc/core@1.3.0: resolution: {integrity: sha512-aPBnND92Itl+SWWbWyyxdFFF0+RqKB6dptGHEdiPB8ZvnHWHlVzOfEvbEcyUYGtB6HBdsfkVuBiaGYyBFVTzVQ==} + dev: false - '@r2wc/react-to-web-component@2.1.0': + /@r2wc/react-to-web-component@2.1.0(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-m/PzgUOEiL1HxmvfP5LgBLqB7sHeRj+d1QAeZklwS4OEI2HUU+xTpT3hhJipH5DQoFInDqDTfe0lNFFKcrqk4w==} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 + dependencies: + '@r2wc/core': 1.3.0 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + dev: false - '@rolldown/pluginutils@1.0.0-beta.38': + /@rolldown/pluginutils@1.0.0-beta.38: resolution: {integrity: sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==} + dev: true - '@rollup/plugin-typescript@12.1.4': + /@rollup/plugin-typescript@12.1.4(tslib@2.8.1)(typescript@5.9.3): resolution: {integrity: sha512-s5Hx+EtN60LMlDBvl5f04bEiFZmAepk27Q+mr85L/00zPDn1jtzlTV6FWn81MaIwqfWzKxmOJrBWHU6vtQyedQ==} engines: {node: '>=14.0.0'} peerDependencies: @@ -639,8 +1068,14 @@ packages: optional: true tslib: optional: true + dependencies: + '@rollup/pluginutils': 5.3.0 + resolve: 1.22.10 + tslib: 2.8.1 + typescript: 5.9.3 + dev: true - '@rollup/pluginutils@5.3.0': + /@rollup/pluginutils@5.3.0: resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} peerDependencies: @@ -648,266 +1083,502 @@ packages: peerDependenciesMeta: rollup: optional: true + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + dev: true - '@rollup/rollup-android-arm-eabi@4.52.4': + /@rollup/rollup-android-arm-eabi@4.52.4: resolution: {integrity: sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==} cpu: [arm] os: [android] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-android-arm64@4.52.4': + /@rollup/rollup-android-arm64@4.52.4: resolution: {integrity: sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==} cpu: [arm64] os: [android] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-darwin-arm64@4.52.4': + /@rollup/rollup-darwin-arm64@4.52.4: resolution: {integrity: sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-darwin-x64@4.52.4': + /@rollup/rollup-darwin-x64@4.52.4: resolution: {integrity: sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-freebsd-arm64@4.52.4': + /@rollup/rollup-freebsd-arm64@4.52.4: resolution: {integrity: sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==} cpu: [arm64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-freebsd-x64@4.52.4': + /@rollup/rollup-freebsd-x64@4.52.4: resolution: {integrity: sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.52.4': + /@rollup/rollup-linux-arm-gnueabihf@4.52.4: resolution: {integrity: sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm-musleabihf@4.52.4': + /@rollup/rollup-linux-arm-musleabihf@4.52.4: resolution: {integrity: sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm64-gnu@4.52.4': + /@rollup/rollup-linux-arm64-gnu@4.52.4: resolution: {integrity: sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm64-musl@4.52.4': + /@rollup/rollup-linux-arm64-musl@4.52.4: resolution: {integrity: sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-loong64-gnu@4.52.4': + /@rollup/rollup-linux-loong64-gnu@4.52.4: resolution: {integrity: sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==} cpu: [loong64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-ppc64-gnu@4.52.4': + /@rollup/rollup-linux-ppc64-gnu@4.52.4: resolution: {integrity: sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-riscv64-gnu@4.52.4': + /@rollup/rollup-linux-riscv64-gnu@4.52.4: resolution: {integrity: sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-riscv64-musl@4.52.4': + /@rollup/rollup-linux-riscv64-musl@4.52.4: resolution: {integrity: sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-s390x-gnu@4.52.4': + /@rollup/rollup-linux-s390x-gnu@4.52.4: resolution: {integrity: sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==} cpu: [s390x] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-x64-gnu@4.52.4': + /@rollup/rollup-linux-x64-gnu@4.52.4: resolution: {integrity: sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-x64-musl@4.52.4': + /@rollup/rollup-linux-x64-musl@4.52.4: resolution: {integrity: sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-openharmony-arm64@4.52.4': + /@rollup/rollup-openharmony-arm64@4.52.4: resolution: {integrity: sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==} cpu: [arm64] os: [openharmony] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-arm64-msvc@4.52.4': + /@rollup/rollup-win32-arm64-msvc@4.52.4: resolution: {integrity: sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-ia32-msvc@4.52.4': + /@rollup/rollup-win32-ia32-msvc@4.52.4: resolution: {integrity: sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==} cpu: [ia32] os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-x64-gnu@4.52.4': + /@rollup/rollup-win32-x64-gnu@4.52.4: resolution: {integrity: sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-x64-msvc@4.52.4': + /@rollup/rollup-win32-x64-msvc@4.52.4: resolution: {integrity: sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@szhsin/react-menu@4.5.0': + /@szhsin/react-menu@4.5.0(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-fblZBPxFGjg+QxSbdDsWk3H8brupuQG+ayYXElwg+FdCxwLQLvrHG9K6O9+4pE8qLyDy5REn/2HmffPXcBZviA==} peerDependencies: react: '>=16.14.0' react-dom: '>=16.14.0' + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-transition-state: 2.3.1(react-dom@19.2.0)(react@19.2.0) + dev: false - '@tsconfig/node10@1.0.11': + /@tsconfig/node10@1.0.11: resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + dev: true - '@tsconfig/node12@1.0.11': + /@tsconfig/node12@1.0.11: resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + dev: true - '@tsconfig/node14@1.0.3': + /@tsconfig/node14@1.0.3: resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + dev: true - '@tsconfig/node16@1.0.4': + /@tsconfig/node16@1.0.4: resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + dev: true - '@types/babel__core@7.20.5': + /@types/babel__core@7.20.5: resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + dev: true - '@types/babel__generator@7.27.0': + /@types/babel__generator@7.27.0: resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + dependencies: + '@babel/types': 7.28.4 + dev: true - '@types/babel__template@7.4.4': + /@types/babel__template@7.4.4: resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + dev: true - '@types/babel__traverse@7.28.0': + /@types/babel__traverse@7.28.0: resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + dependencies: + '@babel/types': 7.28.4 + dev: true - '@types/chai@5.2.2': + /@types/chai@5.2.2: resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} + dependencies: + '@types/deep-eql': 4.0.2 + dev: true - '@types/d3-color@3.1.3': + /@types/d3-color@3.1.3: resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + dev: false - '@types/d3-drag@3.0.7': + /@types/d3-drag@3.0.7: resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: false - '@types/d3-interpolate@3.0.4': + /@types/d3-interpolate@3.0.4: resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + dependencies: + '@types/d3-color': 3.1.3 + dev: false - '@types/d3-selection@3.0.11': + /@types/d3-selection@3.0.11: resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + dev: false - '@types/d3-transition@3.0.9': + /@types/d3-transition@3.0.9: resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: false - '@types/d3-zoom@3.0.8': + /@types/d3-zoom@3.0.8: resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + dev: false - '@types/deep-eql@4.0.2': + /@types/deep-eql@4.0.2: resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + dev: true - '@types/eslint-scope@3.7.7': + /@types/eslint-scope@3.7.7: resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.8 + dev: true - '@types/eslint@9.6.1': + /@types/eslint@9.6.1: resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + dependencies: + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + dev: true - '@types/estree@1.0.8': + /@types/estree@1.0.8: resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + dev: true - '@types/json-schema@7.0.15': + /@types/json-schema@7.0.15: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: true - '@types/node@12.20.55': + /@types/node@12.20.55: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + dev: true - '@types/node@24.7.2': + /@types/node@24.7.2: resolution: {integrity: sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==} + dependencies: + undici-types: 7.14.0 + dev: true - '@types/react-dom@19.2.1': + /@types/react-dom@19.2.1(@types/react@19.2.2): resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} peerDependencies: '@types/react': ^19.2.0 + dependencies: + '@types/react': 19.2.2 + dev: true - '@types/react@19.2.2': + /@types/react@19.2.2: resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==} + dependencies: + csstype: 3.1.3 - '@typescript-eslint/eslint-plugin@8.46.0': + /@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.37.0)(typescript@5.9.3): resolution: {integrity: sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.46.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/type-utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.0 + eslint: 9.37.0 + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + dev: true - '@typescript-eslint/parser@8.46.0': + /@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.9.3): resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.0 + debug: 4.4.3 + eslint: 9.37.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + dev: true - '@typescript-eslint/project-service@8.46.0': + /@typescript-eslint/project-service@8.46.0(typescript@5.9.3): resolution: {integrity: sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) + '@typescript-eslint/types': 8.46.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + dev: true - '@typescript-eslint/scope-manager@8.46.0': + /@typescript-eslint/scope-manager@8.46.0: resolution: {integrity: sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/visitor-keys': 8.46.0 + dev: true - '@typescript-eslint/tsconfig-utils@8.46.0': + /@typescript-eslint/tsconfig-utils@8.46.0(typescript@5.9.3): resolution: {integrity: sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' + dependencies: + typescript: 5.9.3 + dev: true - '@typescript-eslint/type-utils@8.46.0': + /@typescript-eslint/type-utils@8.46.0(eslint@9.37.0)(typescript@5.9.3): resolution: {integrity: sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.37.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + dev: true - '@typescript-eslint/types@8.46.0': + /@typescript-eslint/types@8.46.0: resolution: {integrity: sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true - '@typescript-eslint/typescript-estree@8.46.0': + /@typescript-eslint/typescript-estree@8.46.0(typescript@5.9.3): resolution: {integrity: sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/project-service': 8.46.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/visitor-keys': 8.46.0 + debug: 4.4.3 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.3 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + dev: true - '@typescript-eslint/utils@8.46.0': + /@typescript-eslint/utils@8.46.0(eslint@9.37.0)(typescript@5.9.3): resolution: {integrity: sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + eslint: 9.37.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + dev: true - '@typescript-eslint/visitor-keys@8.46.0': + /@typescript-eslint/visitor-keys@8.46.0: resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.46.0 + eslint-visitor-keys: 4.2.1 + dev: true - '@vitejs/plugin-react@5.0.4': + /@vitejs/plugin-react@5.0.4(vite@7.1.9): resolution: {integrity: sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + dependencies: + '@babel/core': 7.28.4 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) + '@rolldown/pluginutils': 1.0.0-beta.38 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 7.1.9(@types/node@24.7.2) + transitivePeerDependencies: + - supports-color + dev: true - '@vitest/expect@3.2.4': + /@vitest/expect@3.2.4: resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + dependencies: + '@types/chai': 5.2.2 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + tinyrainbow: 2.0.0 + dev: true - '@vitest/mocker@3.2.4': + /@vitest/mocker@3.2.4(vite@7.1.9): resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: msw: ^2.4.9 @@ -917,305 +1588,550 @@ packages: optional: true vite: optional: true + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.19 + vite: 7.1.9(@types/node@24.7.2) + dev: true - '@vitest/pretty-format@3.2.4': + /@vitest/pretty-format@3.2.4: resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + dependencies: + tinyrainbow: 2.0.0 + dev: true - '@vitest/runner@3.2.4': + /@vitest/runner@3.2.4: resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + dependencies: + '@vitest/utils': 3.2.4 + pathe: 2.0.3 + strip-literal: 3.1.0 + dev: true - '@vitest/snapshot@3.2.4': + /@vitest/snapshot@3.2.4: resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + dependencies: + '@vitest/pretty-format': 3.2.4 + magic-string: 0.30.19 + pathe: 2.0.3 + dev: true - '@vitest/spy@3.2.4': + /@vitest/spy@3.2.4: resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + dependencies: + tinyspy: 4.0.4 + dev: true - '@vitest/utils@3.2.4': + /@vitest/utils@3.2.4: resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + dev: true - '@webassemblyjs/ast@1.14.1': + /@webassemblyjs/ast@1.14.1: resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + dev: true - '@webassemblyjs/floating-point-hex-parser@1.13.2': + /@webassemblyjs/floating-point-hex-parser@1.13.2: resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + dev: true - '@webassemblyjs/helper-api-error@1.13.2': + /@webassemblyjs/helper-api-error@1.13.2: resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + dev: true - '@webassemblyjs/helper-buffer@1.14.1': + /@webassemblyjs/helper-buffer@1.14.1: resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + dev: true - '@webassemblyjs/helper-numbers@1.13.2': + /@webassemblyjs/helper-numbers@1.13.2: resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + dev: true - '@webassemblyjs/helper-wasm-bytecode@1.13.2': + /@webassemblyjs/helper-wasm-bytecode@1.13.2: resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + dev: true - '@webassemblyjs/helper-wasm-section@1.14.1': + /@webassemblyjs/helper-wasm-section@1.14.1: resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + dev: true - '@webassemblyjs/ieee754@1.13.2': + /@webassemblyjs/ieee754@1.13.2: resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + dependencies: + '@xtuc/ieee754': 1.2.0 + dev: true - '@webassemblyjs/leb128@1.13.2': + /@webassemblyjs/leb128@1.13.2: resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + dependencies: + '@xtuc/long': 4.2.2 + dev: true - '@webassemblyjs/utf8@1.13.2': + /@webassemblyjs/utf8@1.13.2: resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + dev: true - '@webassemblyjs/wasm-edit@1.14.1': + /@webassemblyjs/wasm-edit@1.14.1: resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + dev: true - '@webassemblyjs/wasm-gen@1.14.1': + /@webassemblyjs/wasm-gen@1.14.1: resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + dev: true - '@webassemblyjs/wasm-opt@1.14.1': + /@webassemblyjs/wasm-opt@1.14.1: resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + dev: true - '@webassemblyjs/wasm-parser@1.14.1': + /@webassemblyjs/wasm-parser@1.14.1: resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + dev: true - '@webassemblyjs/wast-printer@1.14.1': + /@webassemblyjs/wast-printer@1.14.1: resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + dev: true - '@xtuc/ieee754@1.2.0': + /@xtuc/ieee754@1.2.0: resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + dev: true - '@xtuc/long@4.2.2': + /@xtuc/long@4.2.2: resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + dev: true - '@xyflow/react@12.8.6': + /@xyflow/react@12.8.6(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-SksAm2m4ySupjChphMmzvm55djtgMDPr+eovPDdTnyGvShf73cvydfoBfWDFllooIQ4IaiUL5yfxHRwU0c37EA==} peerDependencies: react: '>=17' react-dom: '>=17' + dependencies: + '@xyflow/system': 0.0.70 + classcat: 5.0.5 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + zustand: 4.5.7(@types/react@19.2.2)(react@19.2.0) + transitivePeerDependencies: + - '@types/react' + - immer + dev: false - '@xyflow/system@0.0.70': + /@xyflow/system@0.0.70: resolution: {integrity: sha512-PpC//u9zxdjj0tfTSmZrg3+sRbTz6kop/Amky44U2Dl51sxzDTIUfXMwETOYpmr2dqICWXBIJwXL2a9QWtX2XA==} + dependencies: + '@types/d3-drag': 3.0.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-zoom: 3.0.0 + dev: false - acorn-import-phases@1.0.4: + /acorn-import-phases@1.0.4(acorn@8.15.0): resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} engines: {node: '>=10.13.0'} peerDependencies: acorn: ^8.14.0 + dependencies: + acorn: 8.15.0 + dev: true - acorn-jsx@5.3.2: + /acorn-jsx@5.3.2(acorn@8.15.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.15.0 + dev: true - acorn-walk@8.3.4: + /acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} + dependencies: + acorn: 8.15.0 + dev: true - acorn@8.15.0: + /acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true + dev: true - ajv-formats@2.1.1: + /ajv-formats@2.1.1(ajv@8.17.1): resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: ajv: ^8.0.0 peerDependenciesMeta: ajv: optional: true + dependencies: + ajv: 8.17.1 + dev: true - ajv-keywords@5.1.0: + /ajv-keywords@5.1.0(ajv@8.17.1): resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} peerDependencies: ajv: ^8.8.2 + dependencies: + ajv: 8.17.1 + fast-deep-equal: 3.1.3 + dev: true - ajv@6.12.6: + /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true - ajv@8.17.1: + /ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + dev: true - ansi-colors@4.1.3: + /ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + dev: true - ansi-regex@5.0.1: + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + dev: true - ansi-regex@6.2.2: + /ansi-regex@6.2.2: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} + dev: true - ansi-styles@4.3.0: + /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true - ansi-styles@6.2.3: + /ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + dev: true - arg@4.1.3: + /arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + dev: true - argparse@1.0.10: + /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true - argparse@2.0.1: + /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true - array-union@2.1.0: + /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + dev: true - assertion-error@2.0.1: + /assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + dev: true - balanced-match@1.0.2: + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true - baseline-browser-mapping@2.8.16: + /baseline-browser-mapping@2.8.16: resolution: {integrity: sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==} hasBin: true + dev: true - better-path-resolve@1.0.0: + /better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + dependencies: + is-windows: 1.0.2 + dev: true - brace-expansion@1.1.12: + /brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true - brace-expansion@2.0.2: + /brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + dependencies: + balanced-match: 1.0.2 + dev: true - braces@3.0.3: + /braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + dependencies: + fill-range: 7.1.1 + dev: true - browserslist@4.26.3: + /browserslist@4.26.3: resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + dependencies: + baseline-browser-mapping: 2.8.16 + caniuse-lite: 1.0.30001750 + electron-to-chromium: 1.5.234 + node-releases: 2.0.23 + update-browserslist-db: 1.1.3(browserslist@4.26.3) + dev: true - buffer-from@1.1.2: + /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true - cac@6.7.14: + /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + dev: true - callsites@3.1.0: + /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + dev: true - caniuse-lite@1.0.30001750: + /caniuse-lite@1.0.30001750: resolution: {integrity: sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==} + dev: true - chai@5.3.3: + /chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + dev: true - chalk@4.1.2: + /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true - chalk@5.6.2: + /chalk@5.6.2: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true - chardet@2.1.0: + /chardet@2.1.0: resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==} + dev: true - check-error@2.1.1: + /check-error@2.1.1: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} + dev: true - chokidar@4.0.3: + /chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + dependencies: + readdirp: 4.1.2 + dev: true - chrome-trace-event@1.0.4: + /chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} + dev: true - ci-info@3.9.0: + /ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + dev: true - classcat@5.0.5: + /classcat@5.0.5: resolution: {integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==} + dev: false - color-convert@2.0.1: + /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true - color-name@1.1.4: + /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true - commander@2.20.3: + /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + dev: true - concat-map@0.0.1: + /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true - convert-source-map@2.0.0: + /convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true - create-require@1.1.1: + /create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: true - cross-env@10.1.0: + /cross-env@10.1.0: resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==} engines: {node: '>=20'} hasBin: true + dependencies: + '@epic-web/invariant': 1.0.0 + cross-spawn: 7.0.6 + dev: true - cross-spawn@7.0.6: + /cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true - csstype@3.1.3: + /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - d3-color@3.1.0: + /d3-color@3.1.0: resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} engines: {node: '>=12'} + dev: false - d3-dispatch@3.0.1: + /d3-dispatch@3.0.1: resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} engines: {node: '>=12'} + dev: false - d3-drag@3.0.0: + /d3-drag@3.0.0: resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + dev: false - d3-ease@3.0.1: + /d3-ease@3.0.1: resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} engines: {node: '>=12'} + dev: false - d3-interpolate@3.0.1: + /d3-interpolate@3.0.1: resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} engines: {node: '>=12'} + dependencies: + d3-color: 3.1.0 + dev: false - d3-selection@3.0.0: + /d3-selection@3.0.0: resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} engines: {node: '>=12'} + dev: false - d3-timer@3.0.1: + /d3-timer@3.0.1: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} + dev: false - d3-transition@3.0.1: + /d3-transition@3.0.1(d3-selection@3.0.0): resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} engines: {node: '>=12'} peerDependencies: d3-selection: 2 - 3 + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + dev: false - d3-zoom@3.0.0: + /d3-zoom@3.0.0: resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + dev: false - dataloader@1.4.0: + /dataloader@1.4.0: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} + dev: true - debug@4.4.3: + /debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: @@ -1223,97 +2139,176 @@ packages: peerDependenciesMeta: supports-color: optional: true + dependencies: + ms: 2.1.3 + dev: true - deep-eql@5.0.2: + /deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + dev: true - deep-is@0.1.4: + /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true - detect-indent@6.1.0: + /detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + dev: true - diff@4.0.2: + /diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} + dev: true - dir-glob@3.0.1: + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true - dotenv@8.6.0: + /dotenv@8.6.0: resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} engines: {node: '>=10'} + dev: true - eastasianwidth@0.2.0: + /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true - electron-to-chromium@1.5.234: + /electron-to-chromium@1.5.234: resolution: {integrity: sha512-RXfEp2x+VRYn8jbKfQlRImzoJU01kyDvVPBmG39eU2iuRVhuS6vQNocB8J0/8GrIMLnPzgz4eW6WiRnJkTuNWg==} + dev: true - elkjs@0.11.0: + /elkjs@0.11.0: resolution: {integrity: sha512-u4J8h9mwEDaYMqo0RYJpqNMFDoMK7f+pu4GjcV+N8jIC7TRdORgzkfSjTJemhqONFfH6fBI3wpysgWbhgVWIXw==} + dev: false - emoji-regex@8.0.0: + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true - emoji-regex@9.2.2: + /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true - enhanced-resolve@5.18.3: + /enhanced-resolve@5.18.3: resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} engines: {node: '>=10.13.0'} + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + dev: true - enquirer@2.4.1: + /enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + dev: true - es-module-lexer@1.7.0: + /es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + dev: true - esbuild@0.25.10: + /esbuild@0.25.10: resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} engines: {node: '>=18'} hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.10 + '@esbuild/android-arm': 0.25.10 + '@esbuild/android-arm64': 0.25.10 + '@esbuild/android-x64': 0.25.10 + '@esbuild/darwin-arm64': 0.25.10 + '@esbuild/darwin-x64': 0.25.10 + '@esbuild/freebsd-arm64': 0.25.10 + '@esbuild/freebsd-x64': 0.25.10 + '@esbuild/linux-arm': 0.25.10 + '@esbuild/linux-arm64': 0.25.10 + '@esbuild/linux-ia32': 0.25.10 + '@esbuild/linux-loong64': 0.25.10 + '@esbuild/linux-mips64el': 0.25.10 + '@esbuild/linux-ppc64': 0.25.10 + '@esbuild/linux-riscv64': 0.25.10 + '@esbuild/linux-s390x': 0.25.10 + '@esbuild/linux-x64': 0.25.10 + '@esbuild/netbsd-arm64': 0.25.10 + '@esbuild/netbsd-x64': 0.25.10 + '@esbuild/openbsd-arm64': 0.25.10 + '@esbuild/openbsd-x64': 0.25.10 + '@esbuild/openharmony-arm64': 0.25.10 + '@esbuild/sunos-x64': 0.25.10 + '@esbuild/win32-arm64': 0.25.10 + '@esbuild/win32-ia32': 0.25.10 + '@esbuild/win32-x64': 0.25.10 + dev: true - escalade@3.2.0: + /escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + dev: true - escape-string-regexp@4.0.0: + /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + dev: true - eslint-plugin-react-hooks@7.0.0: + /eslint-plugin-react-hooks@7.0.0(eslint@9.37.0): resolution: {integrity: sha512-fNXaOwvKwq2+pXiRpXc825Vd63+KM4DLL40Rtlycb8m7fYpp6efrTp1sa6ZbP/Ap58K2bEKFXRmhURE+CJAQWw==} engines: {node: '>=18'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + dependencies: + '@babel/core': 7.28.4 + '@babel/parser': 7.28.4 + eslint: 9.37.0 + hermes-parser: 0.25.1 + zod: 4.1.12 + zod-validation-error: 4.0.2(zod@4.1.12) + transitivePeerDependencies: + - supports-color + dev: true - eslint-plugin-react-refresh@0.4.23: + /eslint-plugin-react-refresh@0.4.23(eslint@9.37.0): resolution: {integrity: sha512-G4j+rv0NmbIR45kni5xJOrYvCtyD3/7LjpVH8MPPcudXDcNu8gv+4ATTDXTtbRR8rTCM5HxECvCSsRmxKnWDsA==} peerDependencies: eslint: '>=8.40' + dependencies: + eslint: 9.37.0 + dev: true - eslint-scope@5.1.1: + /eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true - eslint-scope@8.4.0: + /eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true - eslint-visitor-keys@3.4.3: + /eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true - eslint-visitor-keys@4.2.1: + /eslint-visitor-keys@4.2.1: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true - eslint@9.37.0: + /eslint@9.37.0: resolution: {integrity: sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true @@ -1322,73 +2317,148 @@ packages: peerDependenciesMeta: jiti: optional: true + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.0 + '@eslint/config-helpers': 0.4.0 + '@eslint/core': 0.16.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.37.0 + '@eslint/plugin-kit': 0.4.0 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + dev: true - espree@10.4.0: + /espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + dev: true - esprima@4.0.1: + /esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true + dev: true - esquery@1.6.0: + /esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true - esrecurse@4.3.0: + /esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true - estraverse@4.3.0: + /estraverse@4.3.0: resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} engines: {node: '>=4.0'} + dev: true - estraverse@5.3.0: + /estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + dev: true - estree-walker@2.0.2: + /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: true - estree-walker@3.0.3: + /estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + dependencies: + '@types/estree': 1.0.8 + dev: true - esutils@2.0.3: + /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + dev: true - events@3.3.0: + /events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + dev: true - expect-type@1.2.2: + /expect-type@1.2.2: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} + dev: true - extendable-error@0.1.7: + /extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + dev: true - fast-deep-equal@3.1.3: + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true - fast-glob@3.3.3: + /fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + dev: true - fast-json-stable-stringify@2.1.0: + /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true - fast-levenshtein@2.0.6: + /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true - fast-uri@3.1.0: + /fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + dev: true - fastq@1.19.1: + /fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + dependencies: + reusify: 1.1.0 + dev: true - fdir@6.5.0: + /fdir@6.5.0(picomatch@4.0.3): resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} peerDependencies: @@ -1396,314 +2466,497 @@ packages: peerDependenciesMeta: picomatch: optional: true + dependencies: + picomatch: 4.0.3 + dev: true - file-entry-cache@8.0.0: + /file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + dependencies: + flat-cache: 4.0.1 + dev: true - fill-range@7.1.1: + /fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true - find-up@4.1.0: + /find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: true - find-up@5.0.0: + /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true - flat-cache@4.0.1: + /flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + dev: true - flatted@3.3.3: + /flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + dev: true - foreground-child@3.3.1: + /foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + dev: true - fs-extra@7.0.1: + /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: true - fs-extra@8.1.0: + /fs-extra@8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: true - fsevents@2.3.3: + /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + requiresBuild: true + dev: true + optional: true - function-bind@1.1.2: + /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true - gensync@1.0.0-beta.2: + /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + dev: true - glob-parent@5.1.2: + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true - glob-parent@6.0.2: + /glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true - glob-to-regexp@0.4.1: + /glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + dev: true - glob@11.0.3: + /glob@11.0.3: resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} engines: {node: 20 || >=22} hasBin: true + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.1 + minimatch: 10.0.3 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + dev: true - globals@14.0.0: + /globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} + dev: true - globals@16.4.0: + /globals@16.4.0: resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} engines: {node: '>=18'} + dev: true - globby@11.1.0: + /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} - - graceful-fs@4.2.11: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true - graphemer@1.4.0: + /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true - has-flag@4.0.0: + /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + dev: true - hasown@2.0.2: + /hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true - hermes-estree@0.25.1: + /hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + dev: true - hermes-parser@0.25.1: + /hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + dependencies: + hermes-estree: 0.25.1 + dev: true - html-to-image@1.11.13: + /html-to-image@1.11.13: resolution: {integrity: sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg==} + dev: false - human-id@4.1.2: + /human-id@4.1.2: resolution: {integrity: sha512-v/J+4Z/1eIJovEBdlV5TYj1IR+ZiohcYGRY+qN/oC9dAfKzVT023N/Bgw37hrKCoVRBvk3bqyzpr2PP5YeTMSg==} hasBin: true + dev: true - husky@9.1.7: + /husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} hasBin: true + dev: true - iconv-lite@0.7.0: + /iconv-lite@0.7.0: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: true - ignore@5.3.2: + /ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + dev: true - ignore@7.0.5: + /ignore@7.0.5: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} + dev: true - import-fresh@3.3.1: + /import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true - imurmurhash@0.1.4: + /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + dev: true - is-core-module@2.16.1: + /is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.2 + dev: true - is-extglob@2.1.1: + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + dev: true - is-fullwidth-code-point@3.0.0: + /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + dev: true - is-glob@4.0.3: + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true - is-number@7.0.0: + /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + dev: true - is-subdir@1.2.0: + /is-subdir@1.2.0: resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} engines: {node: '>=4'} + dependencies: + better-path-resolve: 1.0.0 + dev: true - is-windows@1.0.2: + /is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} + dev: true - isexe@2.0.0: + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true - jackspeak@4.1.1: + /jackspeak@4.1.1: resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} engines: {node: 20 || >=22} + dependencies: + '@isaacs/cliui': 8.0.2 + dev: true - jest-worker@27.5.1: + /jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} + dependencies: + '@types/node': 24.7.2 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true - js-tokens@4.0.0: + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true - js-tokens@9.0.1: + /js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + dev: true - js-yaml@3.14.1: + /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true - js-yaml@4.1.0: + /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + dependencies: + argparse: 2.0.1 + dev: true - jsesc@3.1.0: + /jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} hasBin: true + dev: true - json-buffer@3.0.1: + /json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true - json-parse-even-better-errors@2.3.1: + /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true - json-schema-traverse@0.4.1: + /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true - json-schema-traverse@1.0.0: + /json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: true - json-stable-stringify-without-jsonify@1.0.1: + /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true - json5@2.2.3: + /json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true + dev: true - jsonfile@4.0.0: + /jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + optionalDependencies: + graceful-fs: 4.2.11 + dev: true - keyv@4.5.4: + /keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true - levn@0.4.1: + /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true - loader-runner@4.3.1: + /loader-runner@4.3.1: resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} + dev: true - locate-path@5.0.0: + /locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: true - locate-path@6.0.0: + /locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true - lodash.merge@4.6.2: + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true - lodash.startcase@4.4.0: + /lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + dev: true - loupe@3.2.1: + /loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + dev: true - lru-cache@11.2.2: + /lru-cache@11.2.2: resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} engines: {node: 20 || >=22} + dev: true - lru-cache@5.1.1: + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true - lucide-react@0.545.0: + /lucide-react@0.545.0(react@19.2.0): resolution: {integrity: sha512-7r1/yUuflQDSt4f1bpn5ZAocyIxcTyVyBBChSVtBKn5M+392cPmI5YJMWOJKk/HUWGm5wg83chlAZtCcGbEZtw==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + dependencies: + react: 19.2.0 + dev: false - magic-string@0.30.19: + /magic-string@0.30.19: resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + dev: true - make-error@1.3.6: + /make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true - merge-stream@2.0.0: + /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true - merge2@1.4.1: + /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + dev: true - micromatch@4.0.8: + /micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + dev: true - mime-db@1.52.0: + /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + dev: true - mime-types@2.1.35: + /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: true - minimatch@10.0.3: + /minimatch@10.0.3: resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} engines: {node: 20 || >=22} + dependencies: + '@isaacs/brace-expansion': 5.0.0 + dev: true - minimatch@3.1.2: + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.12 + dev: true - minimatch@9.0.5: + /minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.2 + dev: true - minipass@7.1.2: + /minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + dev: true - mri@1.2.0: + /mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} + dev: true - ms@2.1.3: + /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true - nanoid@3.3.11: + /nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + dev: true - natural-compare@1.4.0: + /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true - neo-async@2.6.2: + /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + dev: true - node-fetch@2.7.0: + /node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} peerDependencies: @@ -1711,316 +2964,518 @@ packages: peerDependenciesMeta: encoding: optional: true + dependencies: + whatwg-url: 5.0.0 + dev: true - node-releases@2.0.23: + /node-releases@2.0.23: resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} + dev: true - optionator@0.9.4: + /optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + dev: true - outdent@0.5.0: + /outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + dev: true - p-filter@2.1.0: + /p-filter@2.1.0: resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} engines: {node: '>=8'} + dependencies: + p-map: 2.1.0 + dev: true - p-limit@2.3.0: + /p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + dev: true - p-limit@3.1.0: + /p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true - p-locate@4.1.0: + /p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + dev: true - p-locate@5.0.0: + /p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true - p-map@2.1.0: + /p-map@2.1.0: resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} engines: {node: '>=6'} + dev: true - p-try@2.2.0: + /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + dev: true - package-json-from-dist@1.0.1: + /package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + dev: true - package-manager-detector@0.2.11: + /package-manager-detector@0.2.11: resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + dependencies: + quansync: 0.2.11 + dev: true - parent-module@1.0.1: + /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true - path-exists@4.0.0: + /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + dev: true - path-key@3.1.1: + /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + dev: true - path-parse@1.0.7: + /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true - path-scurry@2.0.0: + /path-scurry@2.0.0: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} + dependencies: + lru-cache: 11.2.2 + minipass: 7.1.2 + dev: true - path-type@4.0.0: + /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + dev: true - pathe@2.0.3: + /pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + dev: true - pathval@2.0.1: + /pathval@2.0.1: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} + dev: true - picocolors@1.1.1: + /picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + dev: true - picomatch@2.3.1: + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + dev: true - picomatch@4.0.3: + /picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + dev: true - pify@4.0.1: + /pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + dev: true - postcss@8.5.6: + /postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + dev: true - prelude-ls@1.2.1: + /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + dev: true - prettier-plugin-sort-json@4.1.1: + /prettier-plugin-sort-json@4.1.1(prettier@3.6.2): resolution: {integrity: sha512-uJ49wCzwJ/foKKV4tIPxqi4jFFvwUzw4oACMRG2dcmDhBKrxBv0L2wSKkAqHCmxKCvj0xcCZS4jO2kSJO/tRJw==} engines: {node: '>=18.0.0'} peerDependencies: prettier: ^3.0.0 + dependencies: + prettier: 3.6.2 + dev: true - prettier@2.8.8: + /prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} hasBin: true + dev: true - prettier@3.6.2: + /prettier@3.6.2: resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} engines: {node: '>=14'} hasBin: true + dev: true - pretty-quick@4.2.2: + /pretty-quick@4.2.2(prettier@3.6.2): resolution: {integrity: sha512-uAh96tBW1SsD34VhhDmWuEmqbpfYc/B3j++5MC/6b3Cb8Ow7NJsvKFhg0eoGu2xXX+o9RkahkTK6sUdd8E7g5w==} engines: {node: '>=14'} hasBin: true peerDependencies: prettier: ^3.0.0 + dependencies: + '@pkgr/core': 0.2.9 + ignore: 7.0.5 + mri: 1.2.0 + picocolors: 1.1.1 + picomatch: 4.0.3 + prettier: 3.6.2 + tinyexec: 0.3.2 + tslib: 2.8.1 + dev: true - punycode@2.3.1: + /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + dev: true - quansync@0.2.11: + /quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + dev: true - queue-microtask@1.2.3: + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true - randombytes@2.1.0: + /randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + dev: true - react-dom@19.2.0: + /react-dom@19.2.0(react@19.2.0): resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} peerDependencies: react: ^19.2.0 + dependencies: + react: 19.2.0 + scheduler: 0.27.0 + dev: false - react-refresh@0.17.0: + /react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} + dev: true - react-transition-state@2.3.1: + /react-transition-state@2.3.1(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-Z48el73x+7HUEM131dof9YpcQ5IlM4xB+pKWH/lX3FhxGfQaNTZa16zb7pWkC/y5btTZzXfCtglIJEGc57giOw==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + dev: false - react@19.2.0: + /react@19.2.0: resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} engines: {node: '>=0.10.0'} + dev: false - read-yaml-file@1.1.0: + /read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} + dependencies: + graceful-fs: 4.2.11 + js-yaml: 3.14.1 + pify: 4.0.1 + strip-bom: 3.0.0 + dev: true - readdirp@4.1.2: + /readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + dev: true - require-from-string@2.0.2: + /require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + dev: true - resolve-from@4.0.0: + /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + dev: true - resolve-from@5.0.0: + /resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + dev: true - resolve@1.22.10: + /resolve@1.22.10: resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} engines: {node: '>= 0.4'} hasBin: true + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true - reusify@1.1.0: + /reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true - rimraf@6.0.1: + /rimraf@6.0.1: resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} engines: {node: 20 || >=22} hasBin: true + dependencies: + glob: 11.0.3 + package-json-from-dist: 1.0.1 + dev: true - rollup@4.52.4: + /rollup@4.52.4: resolution: {integrity: sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.52.4 + '@rollup/rollup-android-arm64': 4.52.4 + '@rollup/rollup-darwin-arm64': 4.52.4 + '@rollup/rollup-darwin-x64': 4.52.4 + '@rollup/rollup-freebsd-arm64': 4.52.4 + '@rollup/rollup-freebsd-x64': 4.52.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.4 + '@rollup/rollup-linux-arm-musleabihf': 4.52.4 + '@rollup/rollup-linux-arm64-gnu': 4.52.4 + '@rollup/rollup-linux-arm64-musl': 4.52.4 + '@rollup/rollup-linux-loong64-gnu': 4.52.4 + '@rollup/rollup-linux-ppc64-gnu': 4.52.4 + '@rollup/rollup-linux-riscv64-gnu': 4.52.4 + '@rollup/rollup-linux-riscv64-musl': 4.52.4 + '@rollup/rollup-linux-s390x-gnu': 4.52.4 + '@rollup/rollup-linux-x64-gnu': 4.52.4 + '@rollup/rollup-linux-x64-musl': 4.52.4 + '@rollup/rollup-openharmony-arm64': 4.52.4 + '@rollup/rollup-win32-arm64-msvc': 4.52.4 + '@rollup/rollup-win32-ia32-msvc': 4.52.4 + '@rollup/rollup-win32-x64-gnu': 4.52.4 + '@rollup/rollup-win32-x64-msvc': 4.52.4 + fsevents: 2.3.3 + dev: true - run-parallel@1.2.0: + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true - safe-buffer@5.2.1: + /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true - safer-buffer@2.1.2: + /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true - scheduler@0.27.0: + /scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + dev: false - schema-utils@4.3.3: + /schema-utils@4.3.3: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.17.1 + ajv-formats: 2.1.1(ajv@8.17.1) + ajv-keywords: 5.1.0(ajv@8.17.1) + dev: true - semver@6.3.1: + /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + dev: true - semver@7.7.3: + /semver@7.7.3: resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} hasBin: true + dev: true - serialize-javascript@6.0.2: + /serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + dependencies: + randombytes: 2.1.0 + dev: true - shebang-command@2.0.0: + /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true - shebang-regex@3.0.0: + /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + dev: true - siginfo@2.0.0: + /siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + dev: true - signal-exit@4.1.0: + /signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + dev: true - slash@3.0.0: + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + dev: true - source-map-js@1.2.1: + /source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + dev: true - source-map-support@0.5.21: + /source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true - source-map@0.6.1: + /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + dev: true - spawndamnit@3.0.1: + /spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + dev: true - sprintf-js@1.0.3: + /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true - stackback@0.0.2: + /stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + dev: true - std-env@3.9.0: + /std-env@3.9.0: resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + dev: true - string-width@4.2.3: + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true - string-width@5.1.2: + /string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.2 + dev: true - strip-ansi@6.0.1: + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true - strip-ansi@7.1.2: + /strip-ansi@7.1.2: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} + dependencies: + ansi-regex: 6.2.2 + dev: true - strip-bom@3.0.0: + /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + dev: true - strip-json-comments@3.1.1: + /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + dev: true - strip-literal@3.1.0: + /strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + dependencies: + js-tokens: 9.0.1 + dev: true - supports-color@7.2.0: + /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true - supports-color@8.1.1: + /supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + dev: true - supports-preserve-symlinks-flag@1.0.0: + /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + dev: true - tapable@2.3.0: + /tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} + dev: true - term-size@2.2.1: + /term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} + dev: true - terser-webpack-plugin@5.3.14: + /terser-webpack-plugin@5.3.14(esbuild@0.25.10)(webpack@5.102.1): resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} engines: {node: '>= 10.13.0'} peerDependencies: @@ -2035,48 +3490,79 @@ packages: optional: true uglify-js: optional: true + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + esbuild: 0.25.10 + jest-worker: 27.5.1 + schema-utils: 4.3.3 + serialize-javascript: 6.0.2 + terser: 5.44.0 + webpack: 5.102.1(esbuild@0.25.10) + dev: true - terser@5.44.0: + /terser@5.44.0: resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==} engines: {node: '>=10'} hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: true - tinybench@2.9.0: + /tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + dev: true - tinyexec@0.3.2: + /tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + dev: true - tinyglobby@0.2.15: + /tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + dev: true - tinypool@1.1.1: + /tinypool@1.1.1: resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} engines: {node: ^18.0.0 || >=20.0.0} + dev: true - tinyrainbow@2.0.0: + /tinyrainbow@2.0.0: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} + dev: true - tinyspy@4.0.4: + /tinyspy@4.0.4: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} + dev: true - to-regex-range@5.0.1: + /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true - tr46@0.0.3: + /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: true - ts-api-utils@2.1.0: + /ts-api-utils@2.1.0(typescript@5.9.3): resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' + dependencies: + typescript: 5.9.3 + dev: true - ts-node@10.9.2: + /ts-node@10.9.2(@types/node@24.7.2)(typescript@5.9.3): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: @@ -2089,56 +3575,121 @@ packages: optional: true '@swc/wasm': optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 24.7.2 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.9.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true - tslib@2.8.1: + /tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - type-check@0.4.0: + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true - typescript-eslint@8.46.0: + /typescript-eslint@8.46.0(eslint@9.37.0)(typescript@5.9.3): resolution: {integrity: sha512-6+ZrB6y2bT2DX3K+Qd9vn7OFOJR+xSLDj+Aw/N3zBwUt27uTw2sw2TE2+UcY1RiyBZkaGbTkVg9SSdPNUG6aUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.37.0)(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) + eslint: 9.37.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + dev: true - typescript@5.9.3: + /typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true + dev: true - undici-types@7.14.0: + /undici-types@7.14.0: resolution: {integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==} + dev: true - universalify@0.1.2: + /universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} + dev: true - update-browserslist-db@1.1.3: + /update-browserslist-db@1.1.3(browserslist@4.26.3): resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.26.3 + escalade: 3.2.0 + picocolors: 1.1.1 + dev: true - uri-js@4.4.1: + /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + dev: true - use-sync-external-store@1.6.0: + /use-sync-external-store@1.6.0(react@19.2.0): resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + dependencies: + react: 19.2.0 + dev: false - v8-compile-cache-lib@3.0.1: + /v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + dev: true - vite-node@3.2.4: + /vite-node@3.2.4(@types/node@24.7.2): resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.1.9(@types/node@24.7.2) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + dev: true - vite@7.1.9: + /vite@7.1.9(@types/node@24.7.2): resolution: {integrity: sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -2177,2131 +3728,8 @@ packages: optional: true yaml: optional: true - - vitest@3.2.4: - resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.4 - '@vitest/ui': 3.2.4 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/debug': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - walkdir@0.4.1: - resolution: {integrity: sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==} - engines: {node: '>=6.0.0'} - - watchpack@2.4.4: - resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} - engines: {node: '>=10.13.0'} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - webpack-sources@3.3.3: - resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} - engines: {node: '>=10.13.0'} - - webpack@5.102.1: - resolution: {integrity: sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - zod-validation-error@4.0.2: - resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.25.0 || ^4.0.0 - - zod@4.1.12: - resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} - - zundo@2.3.0: - resolution: {integrity: sha512-4GXYxXA17SIKYhVbWHdSEU04P697IMyVGXrC2TnzoyohEAWytFNOKqOp5gTGvaW93F/PM5Y0evbGtOPF0PWQwQ==} - peerDependencies: - zustand: ^4.3.0 || ^5.0.0 - - zustand@4.5.7: - resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} - engines: {node: '>=12.7.0'} - peerDependencies: - '@types/react': '>=16.8' - immer: '>=9.0.6' - react: '>=16.8' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - - zustand@5.0.8: - resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - -snapshots: - - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.27.1 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.28.4': {} - - '@babel/core@7.28.4': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.4 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.28.3': - dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.27.2': - dependencies: - '@babel/compat-data': 7.28.4 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.26.3 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.27.1': - dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.27.1': {} - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.27.1': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.28.4': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 - - '@babel/parser@7.28.4': - dependencies: - '@babel/types': 7.28.4 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/runtime@7.28.4': {} - - '@babel/template@7.27.2': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - - '@babel/traverse@7.28.4': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.4 - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.28.4': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - - '@changesets/apply-release-plan@7.0.13': - dependencies: - '@changesets/config': 3.1.1 - '@changesets/get-version-range-type': 0.4.0 - '@changesets/git': 3.0.4 - '@changesets/should-skip-package': 0.1.2 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - detect-indent: 6.1.0 - fs-extra: 7.0.1 - lodash.startcase: 4.4.0 - outdent: 0.5.0 - prettier: 2.8.8 - resolve-from: 5.0.0 - semver: 7.7.3 - - '@changesets/assemble-release-plan@6.0.9': - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.1.3 - '@changesets/should-skip-package': 0.1.2 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - semver: 7.7.3 - - '@changesets/changelog-git@0.2.1': - dependencies: - '@changesets/types': 6.1.0 - - '@changesets/changelog-github@0.5.1': - dependencies: - '@changesets/get-github-info': 0.6.0 - '@changesets/types': 6.1.0 - dotenv: 8.6.0 - transitivePeerDependencies: - - encoding - - '@changesets/cli@2.29.7(@types/node@24.7.2)': - dependencies: - '@changesets/apply-release-plan': 7.0.13 - '@changesets/assemble-release-plan': 6.0.9 - '@changesets/changelog-git': 0.2.1 - '@changesets/config': 3.1.1 - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.1.3 - '@changesets/get-release-plan': 4.0.13 - '@changesets/git': 3.0.4 - '@changesets/logger': 0.1.1 - '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.5 - '@changesets/should-skip-package': 0.1.2 - '@changesets/types': 6.1.0 - '@changesets/write': 0.4.0 - '@inquirer/external-editor': 1.0.2(@types/node@24.7.2) - '@manypkg/get-packages': 1.1.3 - ansi-colors: 4.1.3 - ci-info: 3.9.0 - enquirer: 2.4.1 - fs-extra: 7.0.1 - mri: 1.2.0 - p-limit: 2.3.0 - package-manager-detector: 0.2.11 - picocolors: 1.1.1 - resolve-from: 5.0.0 - semver: 7.7.3 - spawndamnit: 3.0.1 - term-size: 2.2.1 - transitivePeerDependencies: - - '@types/node' - - '@changesets/config@3.1.1': - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.1.3 - '@changesets/logger': 0.1.1 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - fs-extra: 7.0.1 - micromatch: 4.0.8 - - '@changesets/errors@0.2.0': - dependencies: - extendable-error: 0.1.7 - - '@changesets/get-dependents-graph@2.1.3': - dependencies: - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - picocolors: 1.1.1 - semver: 7.7.3 - - '@changesets/get-github-info@0.6.0': - dependencies: - dataloader: 1.4.0 - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - - '@changesets/get-release-plan@4.0.13': - dependencies: - '@changesets/assemble-release-plan': 6.0.9 - '@changesets/config': 3.1.1 - '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.5 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - - '@changesets/get-version-range-type@0.4.0': {} - - '@changesets/git@3.0.4': - dependencies: - '@changesets/errors': 0.2.0 - '@manypkg/get-packages': 1.1.3 - is-subdir: 1.2.0 - micromatch: 4.0.8 - spawndamnit: 3.0.1 - - '@changesets/logger@0.1.1': - dependencies: - picocolors: 1.1.1 - - '@changesets/parse@0.4.1': - dependencies: - '@changesets/types': 6.1.0 - js-yaml: 3.14.1 - - '@changesets/pre@2.0.2': - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - fs-extra: 7.0.1 - - '@changesets/read@0.6.5': - dependencies: - '@changesets/git': 3.0.4 - '@changesets/logger': 0.1.1 - '@changesets/parse': 0.4.1 - '@changesets/types': 6.1.0 - fs-extra: 7.0.1 - p-filter: 2.1.0 - picocolors: 1.1.1 - - '@changesets/should-skip-package@0.1.2': - dependencies: - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - - '@changesets/types@4.1.0': {} - - '@changesets/types@6.1.0': {} - - '@changesets/write@0.4.0': - dependencies: - '@changesets/types': 6.1.0 - fs-extra: 7.0.1 - human-id: 4.1.2 - prettier: 2.8.8 - - '@cspotcode/source-map-support@0.8.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - - '@epic-web/invariant@1.0.0': {} - - '@esbuild/aix-ppc64@0.25.10': - optional: true - - '@esbuild/android-arm64@0.25.10': - optional: true - - '@esbuild/android-arm@0.25.10': - optional: true - - '@esbuild/android-x64@0.25.10': - optional: true - - '@esbuild/darwin-arm64@0.25.10': - optional: true - - '@esbuild/darwin-x64@0.25.10': - optional: true - - '@esbuild/freebsd-arm64@0.25.10': - optional: true - - '@esbuild/freebsd-x64@0.25.10': - optional: true - - '@esbuild/linux-arm64@0.25.10': - optional: true - - '@esbuild/linux-arm@0.25.10': - optional: true - - '@esbuild/linux-ia32@0.25.10': - optional: true - - '@esbuild/linux-loong64@0.25.10': - optional: true - - '@esbuild/linux-mips64el@0.25.10': - optional: true - - '@esbuild/linux-ppc64@0.25.10': - optional: true - - '@esbuild/linux-riscv64@0.25.10': - optional: true - - '@esbuild/linux-s390x@0.25.10': - optional: true - - '@esbuild/linux-x64@0.25.10': - optional: true - - '@esbuild/netbsd-arm64@0.25.10': - optional: true - - '@esbuild/netbsd-x64@0.25.10': - optional: true - - '@esbuild/openbsd-arm64@0.25.10': - optional: true - - '@esbuild/openbsd-x64@0.25.10': - optional: true - - '@esbuild/openharmony-arm64@0.25.10': - optional: true - - '@esbuild/sunos-x64@0.25.10': - optional: true - - '@esbuild/win32-arm64@0.25.10': - optional: true - - '@esbuild/win32-ia32@0.25.10': - optional: true - - '@esbuild/win32-x64@0.25.10': - optional: true - - '@eslint-community/eslint-utils@4.9.0(eslint@9.37.0)': - dependencies: - eslint: 9.37.0 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.1': {} - - '@eslint/config-array@0.21.0': - dependencies: - '@eslint/object-schema': 2.1.6 - debug: 4.4.3 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.4.0': - dependencies: - '@eslint/core': 0.16.0 - - '@eslint/core@0.16.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/eslintrc@3.3.1': - dependencies: - ajv: 6.12.6 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.37.0': {} - - '@eslint/object-schema@2.1.6': {} - - '@eslint/plugin-kit@0.4.0': - dependencies: - '@eslint/core': 0.16.0 - levn: 0.4.1 - - '@humanfs/core@0.19.1': {} - - '@humanfs/node@0.16.7': - dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.4.3 - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - - '@inquirer/external-editor@1.0.2(@types/node@24.7.2)': - dependencies: - chardet: 2.1.0 - iconv-lite: 0.7.0 - optionalDependencies: - '@types/node': 24.7.2 - - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 - - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.2 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/source-map@0.3.11': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@manypkg/find-root@1.1.0': - dependencies: - '@babel/runtime': 7.28.4 - '@types/node': 12.20.55 - find-up: 4.1.0 - fs-extra: 8.1.0 - - '@manypkg/get-packages@1.1.3': - dependencies: - '@babel/runtime': 7.28.4 - '@changesets/types': 4.1.0 - '@manypkg/find-root': 1.1.0 - fs-extra: 8.1.0 - globby: 11.1.0 - read-yaml-file: 1.1.0 - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 - - '@pkgr/core@0.2.9': {} - - '@r2wc/core@1.3.0': {} - - '@r2wc/react-to-web-component@2.1.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@r2wc/core': 1.3.0 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - - '@rolldown/pluginutils@1.0.0-beta.38': {} - - '@rollup/plugin-typescript@12.1.4(rollup@4.52.4)(tslib@2.8.1)(typescript@5.9.3)': - dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.4) - resolve: 1.22.10 - typescript: 5.9.3 - optionalDependencies: - rollup: 4.52.4 - tslib: 2.8.1 - - '@rollup/pluginutils@5.3.0(rollup@4.52.4)': - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - optionalDependencies: - rollup: 4.52.4 - - '@rollup/rollup-android-arm-eabi@4.52.4': - optional: true - - '@rollup/rollup-android-arm64@4.52.4': - optional: true - - '@rollup/rollup-darwin-arm64@4.52.4': - optional: true - - '@rollup/rollup-darwin-x64@4.52.4': - optional: true - - '@rollup/rollup-freebsd-arm64@4.52.4': - optional: true - - '@rollup/rollup-freebsd-x64@4.52.4': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.52.4': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.52.4': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.52.4': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.52.4': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.52.4': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.52.4': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.52.4': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.52.4': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.52.4': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.52.4': - optional: true - - '@rollup/rollup-linux-x64-musl@4.52.4': - optional: true - - '@rollup/rollup-openharmony-arm64@4.52.4': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.52.4': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.52.4': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.52.4': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.52.4': - optional: true - - '@szhsin/react-menu@4.5.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-transition-state: 2.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - - '@tsconfig/node10@1.0.11': {} - - '@tsconfig/node12@1.0.11': {} - - '@tsconfig/node14@1.0.3': {} - - '@tsconfig/node16@1.0.4': {} - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.28.4 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.28.4 - - '@types/chai@5.2.2': - dependencies: - '@types/deep-eql': 4.0.2 - - '@types/d3-color@3.1.3': {} - - '@types/d3-drag@3.0.7': - dependencies: - '@types/d3-selection': 3.0.11 - - '@types/d3-interpolate@3.0.4': - dependencies: - '@types/d3-color': 3.1.3 - - '@types/d3-selection@3.0.11': {} - - '@types/d3-transition@3.0.9': - dependencies: - '@types/d3-selection': 3.0.11 - - '@types/d3-zoom@3.0.8': - dependencies: - '@types/d3-interpolate': 3.0.4 - '@types/d3-selection': 3.0.11 - - '@types/deep-eql@4.0.2': {} - - '@types/eslint-scope@3.7.7': - dependencies: - '@types/eslint': 9.6.1 - '@types/estree': 1.0.8 - - '@types/eslint@9.6.1': - dependencies: - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - - '@types/estree@1.0.8': {} - - '@types/json-schema@7.0.15': {} - - '@types/node@12.20.55': {} - - '@types/node@24.7.2': - dependencies: - undici-types: 7.14.0 - - '@types/react-dom@19.2.1(@types/react@19.2.2)': - dependencies: - '@types/react': 19.2.2 - - '@types/react@19.2.2': - dependencies: - csstype: 3.1.3 - - '@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.9.3))(eslint@9.37.0)(typescript@5.9.3)': - dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.46.0 - '@typescript-eslint/type-utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.46.0 - eslint: 9.37.0 - graphemer: 1.4.0 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.46.0 - '@typescript-eslint/types': 8.46.0 - '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.46.0 - debug: 4.4.3 - eslint: 9.37.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.46.0(typescript@5.9.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) - '@typescript-eslint/types': 8.46.0 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@8.46.0': - dependencies: - '@typescript-eslint/types': 8.46.0 - '@typescript-eslint/visitor-keys': 8.46.0 - - '@typescript-eslint/tsconfig-utils@8.46.0(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - - '@typescript-eslint/type-utils@8.46.0(eslint@9.37.0)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.46.0 - '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.37.0 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@8.46.0': {} - - '@typescript-eslint/typescript-estree@8.46.0(typescript@5.9.3)': - dependencies: - '@typescript-eslint/project-service': 8.46.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) - '@typescript-eslint/types': 8.46.0 - '@typescript-eslint/visitor-keys': 8.46.0 - debug: 4.4.3 - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.3 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.46.0(eslint@9.37.0)(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) - '@typescript-eslint/scope-manager': 8.46.0 - '@typescript-eslint/types': 8.46.0 - '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) - eslint: 9.37.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.46.0': - dependencies: - '@typescript-eslint/types': 8.46.0 - eslint-visitor-keys: 4.2.1 - - '@vitejs/plugin-react@5.0.4(vite@7.1.9(@types/node@24.7.2)(terser@5.44.0))': - dependencies: - '@babel/core': 7.28.4 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) - '@rolldown/pluginutils': 1.0.0-beta.38 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 7.1.9(@types/node@24.7.2)(terser@5.44.0) - transitivePeerDependencies: - - supports-color - - '@vitest/expect@3.2.4': - dependencies: - '@types/chai': 5.2.2 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - tinyrainbow: 2.0.0 - - '@vitest/mocker@3.2.4(vite@7.1.9(@types/node@24.7.2)(terser@5.44.0))': - dependencies: - '@vitest/spy': 3.2.4 - estree-walker: 3.0.3 - magic-string: 0.30.19 - optionalDependencies: - vite: 7.1.9(@types/node@24.7.2)(terser@5.44.0) - - '@vitest/pretty-format@3.2.4': - dependencies: - tinyrainbow: 2.0.0 - - '@vitest/runner@3.2.4': - dependencies: - '@vitest/utils': 3.2.4 - pathe: 2.0.3 - strip-literal: 3.1.0 - - '@vitest/snapshot@3.2.4': - dependencies: - '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.19 - pathe: 2.0.3 - - '@vitest/spy@3.2.4': - dependencies: - tinyspy: 4.0.4 - - '@vitest/utils@3.2.4': - dependencies: - '@vitest/pretty-format': 3.2.4 - loupe: 3.2.1 - tinyrainbow: 2.0.0 - - '@webassemblyjs/ast@1.14.1': - dependencies: - '@webassemblyjs/helper-numbers': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - - '@webassemblyjs/floating-point-hex-parser@1.13.2': {} - - '@webassemblyjs/helper-api-error@1.13.2': {} - - '@webassemblyjs/helper-buffer@1.14.1': {} - - '@webassemblyjs/helper-numbers@1.13.2': - dependencies: - '@webassemblyjs/floating-point-hex-parser': 1.13.2 - '@webassemblyjs/helper-api-error': 1.13.2 - '@xtuc/long': 4.2.2 - - '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} - - '@webassemblyjs/helper-wasm-section@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/wasm-gen': 1.14.1 - - '@webassemblyjs/ieee754@1.13.2': - dependencies: - '@xtuc/ieee754': 1.2.0 - - '@webassemblyjs/leb128@1.13.2': - dependencies: - '@xtuc/long': 4.2.2 - - '@webassemblyjs/utf8@1.13.2': {} - - '@webassemblyjs/wasm-edit@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/helper-wasm-section': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-opt': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - '@webassemblyjs/wast-printer': 1.14.1 - - '@webassemblyjs/wasm-gen@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - - '@webassemblyjs/wasm-opt@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - - '@webassemblyjs/wasm-parser@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-api-error': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - - '@webassemblyjs/wast-printer@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@xtuc/long': 4.2.2 - - '@xtuc/ieee754@1.2.0': {} - - '@xtuc/long@4.2.2': {} - - '@xyflow/react@12.8.6(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@xyflow/system': 0.0.70 - classcat: 5.0.5 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - zustand: 4.5.7(@types/react@19.2.2)(react@19.2.0) - transitivePeerDependencies: - - '@types/react' - - immer - - '@xyflow/system@0.0.70': - dependencies: - '@types/d3-drag': 3.0.7 - '@types/d3-interpolate': 3.0.4 - '@types/d3-selection': 3.0.11 - '@types/d3-transition': 3.0.9 - '@types/d3-zoom': 3.0.8 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-zoom: 3.0.0 - - acorn-import-phases@1.0.4(acorn@8.15.0): - dependencies: - acorn: 8.15.0 - - acorn-jsx@5.3.2(acorn@8.15.0): - dependencies: - acorn: 8.15.0 - - acorn-walk@8.3.4: - dependencies: - acorn: 8.15.0 - - acorn@8.15.0: {} - - ajv-formats@2.1.1(ajv@8.17.1): - optionalDependencies: - ajv: 8.17.1 - - ajv-keywords@5.1.0(ajv@8.17.1): - dependencies: - ajv: 8.17.1 - fast-deep-equal: 3.1.3 - - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ajv@8.17.1: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - ansi-colors@4.1.3: {} - - ansi-regex@5.0.1: {} - - ansi-regex@6.2.2: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@6.2.3: {} - - arg@4.1.3: {} - - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - - argparse@2.0.1: {} - - array-union@2.1.0: {} - - assertion-error@2.0.1: {} - - balanced-match@1.0.2: {} - - baseline-browser-mapping@2.8.16: {} - - better-path-resolve@1.0.0: - dependencies: - is-windows: 1.0.2 - - brace-expansion@1.1.12: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.2: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.26.3: - dependencies: - baseline-browser-mapping: 2.8.16 - caniuse-lite: 1.0.30001750 - electron-to-chromium: 1.5.234 - node-releases: 2.0.23 - update-browserslist-db: 1.1.3(browserslist@4.26.3) - - buffer-from@1.1.2: {} - - cac@6.7.14: {} - - callsites@3.1.0: {} - - caniuse-lite@1.0.30001750: {} - - chai@5.3.3: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.1 - deep-eql: 5.0.2 - loupe: 3.2.1 - pathval: 2.0.1 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chalk@5.6.2: {} - - chardet@2.1.0: {} - - check-error@2.1.1: {} - - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - - chrome-trace-event@1.0.4: {} - - ci-info@3.9.0: {} - - classcat@5.0.5: {} - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - commander@2.20.3: {} - - concat-map@0.0.1: {} - - convert-source-map@2.0.0: {} - - create-require@1.1.1: {} - - cross-env@10.1.0: - dependencies: - '@epic-web/invariant': 1.0.0 - cross-spawn: 7.0.6 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - csstype@3.1.3: {} - - d3-color@3.1.0: {} - - d3-dispatch@3.0.1: {} - - d3-drag@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-selection: 3.0.0 - - d3-ease@3.0.1: {} - - d3-interpolate@3.0.1: - dependencies: - d3-color: 3.1.0 - - d3-selection@3.0.0: {} - - d3-timer@3.0.1: {} - - d3-transition@3.0.1(d3-selection@3.0.0): - dependencies: - d3-color: 3.1.0 - d3-dispatch: 3.0.1 - d3-ease: 3.0.1 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-timer: 3.0.1 - - d3-zoom@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) - - dataloader@1.4.0: {} - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - deep-eql@5.0.2: {} - - deep-is@0.1.4: {} - - detect-indent@6.1.0: {} - - diff@4.0.2: {} - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - - dotenv@8.6.0: {} - - eastasianwidth@0.2.0: {} - - electron-to-chromium@1.5.234: {} - - elkjs@0.11.0: {} - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - enhanced-resolve@5.18.3: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.0 - - enquirer@2.4.1: - dependencies: - ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - - es-module-lexer@1.7.0: {} - - esbuild@0.25.10: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.10 - '@esbuild/android-arm': 0.25.10 - '@esbuild/android-arm64': 0.25.10 - '@esbuild/android-x64': 0.25.10 - '@esbuild/darwin-arm64': 0.25.10 - '@esbuild/darwin-x64': 0.25.10 - '@esbuild/freebsd-arm64': 0.25.10 - '@esbuild/freebsd-x64': 0.25.10 - '@esbuild/linux-arm': 0.25.10 - '@esbuild/linux-arm64': 0.25.10 - '@esbuild/linux-ia32': 0.25.10 - '@esbuild/linux-loong64': 0.25.10 - '@esbuild/linux-mips64el': 0.25.10 - '@esbuild/linux-ppc64': 0.25.10 - '@esbuild/linux-riscv64': 0.25.10 - '@esbuild/linux-s390x': 0.25.10 - '@esbuild/linux-x64': 0.25.10 - '@esbuild/netbsd-arm64': 0.25.10 - '@esbuild/netbsd-x64': 0.25.10 - '@esbuild/openbsd-arm64': 0.25.10 - '@esbuild/openbsd-x64': 0.25.10 - '@esbuild/openharmony-arm64': 0.25.10 - '@esbuild/sunos-x64': 0.25.10 - '@esbuild/win32-arm64': 0.25.10 - '@esbuild/win32-ia32': 0.25.10 - '@esbuild/win32-x64': 0.25.10 - - escalade@3.2.0: {} - - escape-string-regexp@4.0.0: {} - - eslint-plugin-react-hooks@7.0.0(eslint@9.37.0): - dependencies: - '@babel/core': 7.28.4 - '@babel/parser': 7.28.4 - eslint: 9.37.0 - hermes-parser: 0.25.1 - zod: 4.1.12 - zod-validation-error: 4.0.2(zod@4.1.12) - transitivePeerDependencies: - - supports-color - - eslint-plugin-react-refresh@0.4.23(eslint@9.37.0): - dependencies: - eslint: 9.37.0 - - eslint-scope@5.1.1: - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - - eslint-scope@8.4.0: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.1: {} - - eslint@9.37.0: - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) - '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.21.0 - '@eslint/config-helpers': 0.4.0 - '@eslint/core': 0.16.0 - '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.37.0 - '@eslint/plugin-kit': 0.4.0 - '@humanfs/node': 0.16.7 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - transitivePeerDependencies: - - supports-color - - espree@10.4.0: - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 4.2.1 - - esprima@4.0.1: {} - - esquery@1.6.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@4.3.0: {} - - estraverse@5.3.0: {} - - estree-walker@2.0.2: {} - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.8 - - esutils@2.0.3: {} - - events@3.3.0: {} - - expect-type@1.2.2: {} - - extendable-error@0.1.7: {} - - fast-deep-equal@3.1.3: {} - - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fast-uri@3.1.0: {} - - fastq@1.19.1: - dependencies: - reusify: 1.1.0 - - fdir@6.5.0(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.3.3 - keyv: 4.5.4 - - flatted@3.3.3: {} - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - fs-extra@7.0.1: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs-extra@8.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - gensync@1.0.0-beta.2: {} - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob-to-regexp@0.4.1: {} - - glob@11.0.3: - dependencies: - foreground-child: 3.3.1 - jackspeak: 4.1.1 - minimatch: 10.0.3 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 2.0.0 - - globals@14.0.0: {} - - globals@16.4.0: {} - - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - - graceful-fs@4.2.11: {} - - graphemer@1.4.0: {} - - has-flag@4.0.0: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - hermes-estree@0.25.1: {} - - hermes-parser@0.25.1: - dependencies: - hermes-estree: 0.25.1 - - html-to-image@1.11.13: {} - - human-id@4.1.2: {} - - husky@9.1.7: {} - - iconv-lite@0.7.0: - dependencies: - safer-buffer: 2.1.2 - - ignore@5.3.2: {} - - ignore@7.0.5: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-number@7.0.0: {} - - is-subdir@1.2.0: - dependencies: - better-path-resolve: 1.0.0 - - is-windows@1.0.2: {} - - isexe@2.0.0: {} - - jackspeak@4.1.1: - dependencies: - '@isaacs/cliui': 8.0.2 - - jest-worker@27.5.1: - dependencies: - '@types/node': 24.7.2 - merge-stream: 2.0.0 - supports-color: 8.1.1 - - js-tokens@4.0.0: {} - - js-tokens@9.0.1: {} - - js-yaml@3.14.1: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - - jsesc@3.1.0: {} - - json-buffer@3.0.1: {} - - json-parse-even-better-errors@2.3.1: {} - - json-schema-traverse@0.4.1: {} - - json-schema-traverse@1.0.0: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - json5@2.2.3: {} - - jsonfile@4.0.0: - optionalDependencies: - graceful-fs: 4.2.11 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - loader-runner@4.3.1: {} - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.merge@4.6.2: {} - - lodash.startcase@4.4.0: {} - - loupe@3.2.1: {} - - lru-cache@11.2.2: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - lucide-react@0.545.0(react@19.2.0): - dependencies: - react: 19.2.0 - - magic-string@0.30.19: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - make-error@1.3.6: {} - - merge-stream@2.0.0: {} - - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - minimatch@10.0.3: - dependencies: - '@isaacs/brace-expansion': 5.0.0 - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.12 - - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.2 - - minipass@7.1.2: {} - - mri@1.2.0: {} - - ms@2.1.3: {} - - nanoid@3.3.11: {} - - natural-compare@1.4.0: {} - - neo-async@2.6.2: {} - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - node-releases@2.0.23: {} - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - outdent@0.5.0: {} - - p-filter@2.1.0: - dependencies: - p-map: 2.1.0 - - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - p-map@2.1.0: {} - - p-try@2.2.0: {} - - package-json-from-dist@1.0.1: {} - - package-manager-detector@0.2.11: - dependencies: - quansync: 0.2.11 - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - path-exists@4.0.0: {} - - path-key@3.1.1: {} - - path-parse@1.0.7: {} - - path-scurry@2.0.0: - dependencies: - lru-cache: 11.2.2 - minipass: 7.1.2 - - path-type@4.0.0: {} - - pathe@2.0.3: {} - - pathval@2.0.1: {} - - picocolors@1.1.1: {} - - picomatch@2.3.1: {} - - picomatch@4.0.3: {} - - pify@4.0.1: {} - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - prelude-ls@1.2.1: {} - - prettier-plugin-sort-json@4.1.1(prettier@3.6.2): - dependencies: - prettier: 3.6.2 - - prettier@2.8.8: {} - - prettier@3.6.2: {} - - pretty-quick@4.2.2(prettier@3.6.2): - dependencies: - '@pkgr/core': 0.2.9 - ignore: 7.0.5 - mri: 1.2.0 - picocolors: 1.1.1 - picomatch: 4.0.3 - prettier: 3.6.2 - tinyexec: 0.3.2 - tslib: 2.8.1 - - punycode@2.3.1: {} - - quansync@0.2.11: {} - - queue-microtask@1.2.3: {} - - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - - react-dom@19.2.0(react@19.2.0): - dependencies: - react: 19.2.0 - scheduler: 0.27.0 - - react-refresh@0.17.0: {} - - react-transition-state@2.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0): - dependencies: - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - - react@19.2.0: {} - - read-yaml-file@1.1.0: - dependencies: - graceful-fs: 4.2.11 - js-yaml: 3.14.1 - pify: 4.0.1 - strip-bom: 3.0.0 - - readdirp@4.1.2: {} - - require-from-string@2.0.2: {} - - resolve-from@4.0.0: {} - - resolve-from@5.0.0: {} - - resolve@1.22.10: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - reusify@1.1.0: {} - - rimraf@6.0.1: - dependencies: - glob: 11.0.3 - package-json-from-dist: 1.0.1 - - rollup@4.52.4: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.4 - '@rollup/rollup-android-arm64': 4.52.4 - '@rollup/rollup-darwin-arm64': 4.52.4 - '@rollup/rollup-darwin-x64': 4.52.4 - '@rollup/rollup-freebsd-arm64': 4.52.4 - '@rollup/rollup-freebsd-x64': 4.52.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.4 - '@rollup/rollup-linux-arm-musleabihf': 4.52.4 - '@rollup/rollup-linux-arm64-gnu': 4.52.4 - '@rollup/rollup-linux-arm64-musl': 4.52.4 - '@rollup/rollup-linux-loong64-gnu': 4.52.4 - '@rollup/rollup-linux-ppc64-gnu': 4.52.4 - '@rollup/rollup-linux-riscv64-gnu': 4.52.4 - '@rollup/rollup-linux-riscv64-musl': 4.52.4 - '@rollup/rollup-linux-s390x-gnu': 4.52.4 - '@rollup/rollup-linux-x64-gnu': 4.52.4 - '@rollup/rollup-linux-x64-musl': 4.52.4 - '@rollup/rollup-openharmony-arm64': 4.52.4 - '@rollup/rollup-win32-arm64-msvc': 4.52.4 - '@rollup/rollup-win32-ia32-msvc': 4.52.4 - '@rollup/rollup-win32-x64-gnu': 4.52.4 - '@rollup/rollup-win32-x64-msvc': 4.52.4 - fsevents: 2.3.3 - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - safe-buffer@5.2.1: {} - - safer-buffer@2.1.2: {} - - scheduler@0.27.0: {} - - schema-utils@4.3.3: - dependencies: - '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) - - semver@6.3.1: {} - - semver@7.7.3: {} - - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - siginfo@2.0.0: {} - - signal-exit@4.1.0: {} - - slash@3.0.0: {} - - source-map-js@1.2.1: {} - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - - spawndamnit@3.0.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - sprintf-js@1.0.3: {} - - stackback@0.0.2: {} - - std-env@3.9.0: {} - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.2 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.1.2: - dependencies: - ansi-regex: 6.2.2 - - strip-bom@3.0.0: {} - - strip-json-comments@3.1.1: {} - - strip-literal@3.1.0: - dependencies: - js-tokens: 9.0.1 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-color@8.1.1: - dependencies: - has-flag: 4.0.0 - - supports-preserve-symlinks-flag@1.0.0: {} - - tapable@2.3.0: {} - - term-size@2.2.1: {} - - terser-webpack-plugin@5.3.14(esbuild@0.25.10)(webpack@5.102.1(esbuild@0.25.10)): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - jest-worker: 27.5.1 - schema-utils: 4.3.3 - serialize-javascript: 6.0.2 - terser: 5.44.0 - webpack: 5.102.1(esbuild@0.25.10) - optionalDependencies: - esbuild: 0.25.10 - - terser@5.44.0: dependencies: - '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 - commander: 2.20.3 - source-map-support: 0.5.21 - - tinybench@2.9.0: {} - - tinyexec@0.3.2: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - - tinypool@1.1.1: {} - - tinyrainbow@2.0.0: {} - - tinyspy@4.0.4: {} - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - tr46@0.0.3: {} - - ts-api-utils@2.1.0(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - - ts-node@10.9.2(@types/node@24.7.2)(typescript@5.9.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 '@types/node': 24.7.2 - acorn: 8.15.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.9.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - - tslib@2.8.1: {} - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - typescript-eslint@8.46.0(eslint@9.37.0)(typescript@5.9.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.9.3))(eslint@9.37.0)(typescript@5.9.3) - '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) - eslint: 9.37.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - typescript@5.9.3: {} - - undici-types@7.14.0: {} - - universalify@0.1.2: {} - - update-browserslist-db@1.1.3(browserslist@4.26.3): - dependencies: - browserslist: 4.26.3 - escalade: 3.2.0 - picocolors: 1.1.1 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - use-sync-external-store@1.6.0(react@19.2.0): - dependencies: - react: 19.2.0 - - v8-compile-cache-lib@3.0.1: {} - - vite-node@3.2.4(@types/node@24.7.2)(terser@5.44.0): - dependencies: - cac: 6.7.14 - debug: 4.4.3 - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 7.1.9(@types/node@24.7.2)(terser@5.44.0) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vite@7.1.9(@types/node@24.7.2)(terser@5.44.0): - dependencies: esbuild: 0.25.10 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 @@ -4309,15 +3737,41 @@ snapshots: rollup: 4.52.4 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.7.2 fsevents: 2.3.3 - terser: 5.44.0 + dev: true - vitest@3.2.4(@types/node@24.7.2)(terser@5.44.0): + /vitest@3.2.4(@types/node@24.7.2): + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.4 + '@vitest/ui': 3.2.4 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true dependencies: '@types/chai': 5.2.2 + '@types/node': 24.7.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.9(@types/node@24.7.2)(terser@5.44.0)) + '@vitest/mocker': 3.2.4(vite@7.1.9) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -4335,11 +3789,9 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.1.9(@types/node@24.7.2)(terser@5.44.0) - vite-node: 3.2.4(@types/node@24.7.2)(terser@5.44.0) + vite: 7.1.9(@types/node@24.7.2) + vite-node: 3.2.4(@types/node@24.7.2) why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 24.7.2 transitivePeerDependencies: - jiti - less @@ -4353,19 +3805,39 @@ snapshots: - terser - tsx - yaml + dev: true - walkdir@0.4.1: {} + /walkdir@0.4.1: + resolution: {integrity: sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==} + engines: {node: '>=6.0.0'} + dev: true - watchpack@2.4.4: + /watchpack@2.4.4: + resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} + engines: {node: '>=10.13.0'} dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 + dev: true - webidl-conversions@3.0.1: {} + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: true - webpack-sources@3.3.3: {} + /webpack-sources@3.3.3: + resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} + engines: {node: '>=10.13.0'} + dev: true - webpack@5.102.1(esbuild@0.25.10): + /webpack@5.102.1(esbuild@0.25.10): + resolution: {integrity: sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -4389,67 +3861,135 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(esbuild@0.25.10)(webpack@5.102.1(esbuild@0.25.10)) + terser-webpack-plugin: 5.3.14(esbuild@0.25.10)(webpack@5.102.1) watchpack: 2.4.4 webpack-sources: 3.3.3 transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js + dev: true - whatwg-url@5.0.0: + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 + dev: true - which@2.0.2: + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true dependencies: isexe: 2.0.0 + dev: true - why-is-node-running@2.3.0: + /why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true dependencies: siginfo: 2.0.0 stackback: 0.0.2 + dev: true - word-wrap@1.2.5: {} + /word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + dev: true - wrap-ansi@7.0.0: + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 + dev: true - wrap-ansi@8.1.0: + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} dependencies: ansi-styles: 6.2.3 string-width: 5.1.2 strip-ansi: 7.1.2 + dev: true - yallist@3.1.1: {} + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true - yn@3.1.1: {} + /yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + dev: true - yocto-queue@0.1.0: {} + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true - zod-validation-error@4.0.2(zod@4.1.12): + /zod-validation-error@4.0.2(zod@4.1.12): + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 dependencies: zod: 4.1.12 + dev: true - zod@4.1.12: {} + /zod@4.1.12: + resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} + dev: true - zundo@2.3.0(zustand@5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0))): + /zundo@2.3.0(zustand@5.0.8): + resolution: {integrity: sha512-4GXYxXA17SIKYhVbWHdSEU04P697IMyVGXrC2TnzoyohEAWytFNOKqOp5gTGvaW93F/PM5Y0evbGtOPF0PWQwQ==} + peerDependencies: + zustand: ^4.3.0 || ^5.0.0 dependencies: - zustand: 5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) + zustand: 5.0.8(@types/react@19.2.2)(react@19.2.0) + dev: false - zustand@4.5.7(@types/react@19.2.2)(react@19.2.0): + /zustand@4.5.7(@types/react@19.2.2)(react@19.2.0): + resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true dependencies: - use-sync-external-store: 1.6.0(react@19.2.0) - optionalDependencies: '@types/react': 19.2.2 react: 19.2.0 + use-sync-external-store: 1.6.0(react@19.2.0) + dev: false - zustand@5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)): - optionalDependencies: + /zustand@5.0.8(@types/react@19.2.2)(react@19.2.0): + resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + dependencies: '@types/react': 19.2.2 react: 19.2.0 - use-sync-external-store: 1.6.0(react@19.2.0) + dev: false From 6f0d019e8640f5d2a232e275fd0c24cbf289645d Mon Sep 17 00:00:00 2001 From: Mike Barkmin Date: Mon, 13 Oct 2025 23:27:38 +0200 Subject: [PATCH 16/17] add persit and improve stuff --- packages/learningmap/package.json | 3 + packages/learningmap/src/DebugModeEdges.tsx | 67 --- packages/learningmap/src/EditorCanvas.tsx | 66 +-- packages/learningmap/src/EditorDrawer.tsx | 8 +- packages/learningmap/src/EditorToolbar.tsx | 24 +- .../learningmap/src/LearningMapEditor.tsx | 40 +- packages/learningmap/src/editorStore.ts | 557 +++++++++++------- packages/learningmap/src/index.css | 6 + 8 files changed, 389 insertions(+), 382 deletions(-) delete mode 100644 packages/learningmap/src/DebugModeEdges.tsx diff --git a/packages/learningmap/package.json b/packages/learningmap/package.json index 85b3882..96e58ef 100644 --- a/packages/learningmap/package.json +++ b/packages/learningmap/package.json @@ -36,10 +36,12 @@ "@szhsin/react-menu": "^4.5.0", "@xyflow/react": "^12.8.6", "elkjs": "^0.11.0", + "fast-deep-equal": "^3.1.3", "html-to-image": "1.11.13", "lucide-react": "^0.545.0", "react": "^19.2.0", "react-dom": "^19.2.0", + "throttle-debounce": "^5.0.2", "tslib": "^2.8.1", "zundo": "^2.3.0", "zustand": "^5.0.8" @@ -47,6 +49,7 @@ "devDependencies": { "@types/react": "^19.2.2", "@types/react-dom": "^19.2.1", + "@types/throttle-debounce": "^5.0.2", "vitest": "^3.0.5" } } diff --git a/packages/learningmap/src/DebugModeEdges.tsx b/packages/learningmap/src/DebugModeEdges.tsx deleted file mode 100644 index acb7399..0000000 --- a/packages/learningmap/src/DebugModeEdges.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { useEffect } from "react"; -import { Edge } from "@xyflow/react"; -import { useEditorStore } from "./editorStore"; - -export const DebugModeEdges = () => { - const nodes = useEditorStore(state => state.nodes); - const debugMode = useEditorStore(state => state.debugMode); - const showCompletionNeeds = useEditorStore(state => state.showCompletionNeeds); - const showCompletionOptional = useEditorStore(state => state.showCompletionOptional); - const showUnlockAfter = useEditorStore(state => state.showUnlockAfter); - const setEdges = useEditorStore(state => state.setEdges); - - useEffect(() => { - // Filter out existing debug edges, but use the store's edges directly to avoid dependency loop - const baseEdges = useEditorStore.getState().edges.filter((e) => !e.id.startsWith("debug-")); - const newEdges: Edge[] = [...baseEdges]; - - if (debugMode) { - nodes.forEach((node) => { - if (showCompletionNeeds && node.type === "topic" && node.data?.completion?.needs) { - node.data.completion.needs.forEach((needId: string) => { - const edgeId = `debug-edge-${needId}-to-${node.id}`; - newEdges.push({ - id: edgeId, - target: needId, - source: node.id, - animated: true, - style: { stroke: "#f97316", strokeWidth: 2, strokeDasharray: "5,5" }, - type: "floating", - }); - }); - } - if (showCompletionOptional && node.data?.completion?.optional) { - node.data.completion.optional.forEach((optionalId: string) => { - const edgeId = `debug-edge-optional-${optionalId}-to-${node.id}`; - newEdges.push({ - id: edgeId, - target: optionalId, - source: node.id, - animated: true, - style: { stroke: "#eab308", strokeWidth: 2, strokeDasharray: "5,5" }, - type: "floating", - }); - }); - } - }); - nodes.forEach((node) => { - if (showUnlockAfter && node.data.unlock?.after) { - node.data.unlock.after.forEach((unlockId: string) => { - const edgeId = `debug-edge-${unlockId}-to-${node.id}`; - newEdges.push({ - id: edgeId, - target: unlockId, - source: node.id, - animated: true, - style: { stroke: "#10b981", strokeWidth: 2, strokeDasharray: "5,5" }, - type: "floating", - }); - }); - } - }); - } - setEdges(newEdges); - }, [nodes, debugMode, showCompletionNeeds, showCompletionOptional, showUnlockAfter, setEdges]); - - return null; -}; diff --git a/packages/learningmap/src/EditorCanvas.tsx b/packages/learningmap/src/EditorCanvas.tsx index a11bb8e..5abb721 100644 --- a/packages/learningmap/src/EditorCanvas.tsx +++ b/packages/learningmap/src/EditorCanvas.tsx @@ -1,6 +1,6 @@ -import React, { useCallback, memo } from "react"; -import { ReactFlow, Controls, Background, ControlButton, Panel, OnNodesChange, OnEdgesChange, OnSelectionChangeFunc } from "@xyflow/react"; -import { Info, Redo, Undo, RotateCw, ShieldAlert } from "lucide-react"; +import { useCallback, memo } from "react"; +import { ReactFlow, Controls, Background, ControlButton, OnSelectionChangeFunc, Node, Edge } from "@xyflow/react"; +import { Info, Redo, Undo } from "lucide-react"; import { useEditorStore, useTemporalStore } from "./editorStore"; import { TaskNode } from "./nodes/TaskNode"; import { TopicNode } from "./nodes/TopicNode"; @@ -9,6 +9,7 @@ import { TextNode } from "./nodes/TextNode"; import FloatingEdge from "./FloatingEdge"; import { MultiNodePanel } from "./MultiNodePanel"; import { getTranslations } from "./translations"; +import { NodeData } from "./types"; const nodeTypes = { topic: TopicNode, @@ -32,9 +33,7 @@ export const EditorCanvas = memo(({ defaultLanguage = "en" }: EditorCanvasProps) const edges = useEditorStore(state => state.edges); const showGrid = useEditorStore(state => state.showGrid); const selectedNodeIds = useEditorStore(state => state.selectedNodeIds); - const selectedNodeId = useEditorStore(state => state.selectedNodeId); - const selectedEdge = useEditorStore(state => state.selectedEdge); - + // Get actions from store const onNodesChange = useEditorStore(state => state.onNodesChange); const onEdgesChange = useEditorStore(state => state.onEdgesChange); @@ -45,72 +44,38 @@ export const EditorCanvas = memo(({ defaultLanguage = "en" }: EditorCanvasProps) const setDrawerOpen = useEditorStore(state => state.setDrawerOpen); const setEdgeDrawerOpen = useEditorStore(state => state.setEdgeDrawerOpen); const setHelpOpen = useEditorStore(state => state.setHelpOpen); - const updateNodes = useEditorStore(state => state.updateNodes); - const getRoadmapData = useEditorStore(state => state.getRoadmapData); - + const language = settings?.language || defaultLanguage; const t = getTranslations(language); - + // Temporal store for undo/redo - const { undo, redo } = useTemporalStore((state) => ({ + const { undo, redo, canUndo, canRedo } = useTemporalStore((state) => ({ undo: state.undo, redo: state.redo, + canUndo: state.pastStates.length > 0, + canRedo: state.futureStates.length > 0, })); - const canUndo = useTemporalStore((state) => state.pastStates.length > 0); - const canRedo = useTemporalStore((state) => state.futureStates.length > 0); - const handleNodeClick = useCallback((event: any, node: any) => { + const handleNodeClick = useCallback((_: any, node: Node) => { setSelectedNodeId(node.id); setDrawerOpen(true); setSelectedEdge(null); setEdgeDrawerOpen(false); }, [setSelectedNodeId, setDrawerOpen, setSelectedEdge, setEdgeDrawerOpen]); - const handleEdgeClick = useCallback((event: any, edge: any) => { + const handleEdgeClick = useCallback((_: any, edge: Edge) => { setSelectedEdge(edge); setEdgeDrawerOpen(true); setSelectedNodeId(null); setDrawerOpen(false); }, [setSelectedEdge, setEdgeDrawerOpen, setSelectedNodeId, setDrawerOpen]); - const handleSave = useCallback(() => { - const roadmapData = getRoadmapData(); - const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(roadmapData, null, 2)); - const downloadAnchorNode = document.createElement('a'); - downloadAnchorNode.setAttribute("href", dataStr); - downloadAnchorNode.setAttribute("download", "learningmap.json"); - document.body.appendChild(downloadAnchorNode); - downloadAnchorNode.click(); - downloadAnchorNode.remove(); - }, [getRoadmapData]); - - const handleNodesChange: OnNodesChange = useCallback( - (changes) => { - onNodesChange(changes); - }, - [onNodesChange] - ); - - const handleEdgesChange: OnEdgesChange = useCallback( - (changes) => { - onEdgesChange(changes); - }, - [onEdgesChange] - ); - const handleSelectionChange: OnSelectionChangeFunc = useCallback( ({ nodes: selectedNodes }) => { setSelectedNodeIds(selectedNodes.map(n => n.id)); }, [setSelectedNodeIds] ); - - const handleUpdateNodes = useCallback( - (updatedNodes: any[]) => { - updateNodes(updatedNodes); - }, - [updateNodes] - ); const defaultEdgeOptions = { animated: false, @@ -131,10 +96,10 @@ export const EditorCanvas = memo(({ defaultLanguage = "en" }: EditorCanvasProps) redo()}> - - - setHelpOpen(true)}> diff --git a/packages/learningmap/src/EditorDrawer.tsx b/packages/learningmap/src/EditorDrawer.tsx index e65a6e9..4c380f6 100644 --- a/packages/learningmap/src/EditorDrawer.tsx +++ b/packages/learningmap/src/EditorDrawer.tsx @@ -21,18 +21,18 @@ export const EditorDrawer: React.FC = ({ const nodes = useEditorStore(state => state.nodes); const isOpen = useEditorStore(state => state.drawerOpen); const settings = useEditorStore(state => state.settings); - + // Get actions from store const setDrawerOpen = useEditorStore(state => state.setDrawerOpen); const setSelectedNodeId = useEditorStore(state => state.setSelectedNodeId); const updateNode = useEditorStore(state => state.updateNode); const deleteNode = useEditorStore(state => state.deleteNode); - + const language = settings?.language || defaultLanguage; const t = getTranslations(language); - + const node = nodes.find(n => n.id === selectedNodeId) || null; - + const [localNode, setLocalNode] = useState | null>(node); useEffect(() => { diff --git a/packages/learningmap/src/EditorToolbar.tsx b/packages/learningmap/src/EditorToolbar.tsx index fc76168..82c7a18 100644 --- a/packages/learningmap/src/EditorToolbar.tsx +++ b/packages/learningmap/src/EditorToolbar.tsx @@ -22,7 +22,7 @@ export const EditorToolbar: React.FC = ({ const showCompletionNeeds = useEditorStore(state => state.showCompletionNeeds); const showCompletionOptional = useEditorStore(state => state.showCompletionOptional); const showUnlockAfter = useEditorStore(state => state.showUnlockAfter); - + // Get actions directly from store const setDebugMode = useEditorStore(state => state.setDebugMode); const setPreviewMode = useEditorStore(state => state.setPreviewMode); @@ -33,10 +33,7 @@ export const EditorToolbar: React.FC = ({ const setSettingsDrawerOpen = useEditorStore(state => state.setSettingsDrawerOpen); const getRoadmapData = useEditorStore(state => state.getRoadmapData); const setShareDialogOpen = useEditorStore(state => state.setShareDialogOpen); - const setLoadExternalDialogOpen = useEditorStore(state => state.setLoadExternalDialogOpen); - const setNodes = useEditorStore(state => state.setNodes); - const setEdges = useEditorStore(state => state.setEdges); - const setSettings = useEditorStore(state => state.setSettings); + const reset = useEditorStore(state => state.reset); const language = settings?.language || defaultLanguage; const t = getTranslations(language); @@ -46,7 +43,7 @@ export const EditorToolbar: React.FC = ({ const onSetShowCompletionNeeds = (checked: boolean) => setShowCompletionNeeds(checked); const onSetShowCompletionOptional = (checked: boolean) => setShowCompletionOptional(checked); const onSetShowUnlockAfter = (checked: boolean) => setShowUnlockAfter(checked); - + const onAddNewNode = (type: "task" | "topic" | "image" | "text") => { const position = { x: Math.random() * 500, y: Math.random() * 500 }; const newNode: Node = { @@ -60,9 +57,9 @@ export const EditorToolbar: React.FC = ({ }; addNode(newNode); }; - + const onOpenSettingsDrawer = () => setSettingsDrawerOpen(true); - + const onDownload = () => { const roadmapData = getRoadmapData(); const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(roadmapData, null, 2)); @@ -73,7 +70,7 @@ export const EditorToolbar: React.FC = ({ downloadAnchorNode.click(); downloadAnchorNode.remove(); }; - + const onOpen = () => { const input = document.createElement('input'); input.type = 'file'; @@ -95,15 +92,12 @@ export const EditorToolbar: React.FC = ({ }; input.click(); }; - + const onShare = () => setShareDialogOpen(true); - + const onReset = () => { if (confirm(t.resetMapWarning)) { - // Reset all state - setNodes([]); - setEdges([]); - setSettings({}); + reset(); } }; diff --git a/packages/learningmap/src/LearningMapEditor.tsx b/packages/learningmap/src/LearningMapEditor.tsx index 624647f..c69d66d 100644 --- a/packages/learningmap/src/LearningMapEditor.tsx +++ b/packages/learningmap/src/LearningMapEditor.tsx @@ -1,6 +1,4 @@ -import { useEffect } from "react"; import { - useReactFlow, ReactFlowProvider, } from "@xyflow/react"; import { EditorDrawer } from "./EditorDrawer"; @@ -8,16 +6,12 @@ import { EdgeDrawer } from "./EdgeDrawer"; import { RoadmapData } from "./types"; import { SettingsDrawer } from "./SettingsDrawer"; import { EditorToolbar } from "./EditorToolbar"; -import { parseRoadmapData } from "./helper"; import { LearningMap } from "./LearningMap"; import { useEditorStore } from "./editorStore"; -import { getTranslations } from "./translations"; import { WelcomeMessage } from "./WelcomeMessage"; import { EditorCanvas } from "./EditorCanvas"; import { EditorDialogs } from "./EditorDialogs"; -import { DebugModeEdges } from "./DebugModeEdges"; import { KeyboardShortcuts } from "./KeyboardShortcuts"; -import { useEditorActions } from "./useEditorActions"; export interface LearningMapEditorProps { roadmapData?: string | RoadmapData; @@ -27,65 +21,43 @@ export interface LearningMapEditorProps { } export function LearningMapEditor({ - roadmapData, language = "en", - onChange, jsonStore = "https://json.openpatch.org", }: LearningMapEditorProps) { - - const parsedRoadmap = parseRoadmapData(roadmapData || ""); - // Only get minimal state needed in this component const nodes = useEditorStore(state => state.nodes); const edges = useEditorStore(state => state.edges); const settings = useEditorStore(state => state.settings); const previewMode = useEditorStore(state => state.previewMode); - + // Store actions - const loadRoadmapData = useEditorStore(state => state.loadRoadmapData); const getRoadmapData = useEditorStore(state => state.getRoadmapData); // Use language from settings if available, otherwise use prop const effectiveLanguage = settings?.language || language; - // Load roadmap data when prop changes - useEffect(() => { - loadRoadmapData(parsedRoadmap); - }, [roadmapData, loadRoadmapData]); - - // Save changes via onChange callback - useEffect(() => { - if (onChange) { - const roadmapData = getRoadmapData(); - onChange(roadmapData); - } - }, [nodes, edges, settings, onChange, getRoadmapData]); - return ( <> - {/* Debug mode edges effect */} - - {/* Keyboard shortcuts handler */} - + {/* Toolbar */} - + {/* Preview or Edit mode */} {previewMode && } {!previewMode && <> {/* Welcome message when empty */} {nodes.length === 0 && edges.length === 0 && } - + {/* Main canvas */} - + {/* Drawers */} - + {/* Dialogs */} } diff --git a/packages/learningmap/src/editorStore.ts b/packages/learningmap/src/editorStore.ts index cd7ec48..62cc3a3 100644 --- a/packages/learningmap/src/editorStore.ts +++ b/packages/learningmap/src/editorStore.ts @@ -1,9 +1,21 @@ -import { create } from 'zustand'; -import { temporal } from 'zundo'; -import { useStoreWithEqualityFn } from 'zustand/traditional'; -import type { TemporalState } from 'zundo'; -import { Node, Edge, applyNodeChanges, applyEdgeChanges, addEdge, NodeChange, EdgeChange, Connection } from '@xyflow/react'; -import { NodeData, RoadmapData, Settings, ImageNodeData, TextNodeData } from './types'; +import { create } from "zustand"; +import { persist } from "zustand/middleware"; +import { temporal } from "zundo"; +import { useStoreWithEqualityFn } from "zustand/traditional"; +import isDeepEqual from "fast-deep-equal"; +import { throttle } from "throttle-debounce"; +import type { TemporalState } from "zundo"; +import { + Node, + Edge, + applyNodeChanges, + applyEdgeChanges, + addEdge, + NodeChange, + EdgeChange, + Connection, +} from "@xyflow/react"; +import { NodeData, RoadmapData, Settings } from "./types"; // Note: This is a global store for the editor. Typically only one editor instance is active at a time. // If you need multiple independent editor instances, consider creating store instances per component or using context. @@ -12,9 +24,8 @@ export interface EditorState { nodes: Node[]; edges: Edge[]; settings: Settings; - + // UI state - saved: boolean; previewMode: boolean; debugMode: boolean; showGrid: boolean; @@ -24,24 +35,24 @@ export interface EditorState { edgeDrawerOpen: boolean; shareDialogOpen: boolean; loadExternalDialogOpen: boolean; - + // Selected items selectedNodeId: string | null; selectedNodeIds: string[]; selectedEdge: Edge | null; - + // Other state nextNodeId: number; clipboard: { nodes: Node[]; edges: Edge[] } | null; lastMousePosition: { x: number; y: number } | null; shareLink: string; pendingExternalId: string | null; - + // Debug settings showCompletionNeeds: boolean; showCompletionOptional: boolean; showUnlockAfter: boolean; - + // Actions onNodesChange: (changes: NodeChange>[]) => void; onEdgesChange: (changes: EdgeChange[]) => void; @@ -53,12 +64,12 @@ export interface EditorState { updateNodeData: (nodeId: string, dataUpdates: Partial) => void; updateNodes: (updates: Node[]) => void; updateEdge: (edgeId: string, updates: Partial) => void; + updateDebugEdges: () => void; deleteNode: (nodeId: string) => void; deleteEdge: (edgeId: string) => void; addNode: (node: Node) => void; - + // UI state setters - setSaved: (saved: boolean) => void; setPreviewMode: (previewMode: boolean) => void; setDebugMode: (debugMode: boolean) => void; setShowGrid: (showGrid: boolean) => void; @@ -72,14 +83,16 @@ export interface EditorState { setSelectedNodeIds: (nodeIds: string[]) => void; setSelectedEdge: (edge: Edge | null) => void; setNextNodeId: (nextNodeId: number) => void; - setClipboard: (clipboard: { nodes: Node[]; edges: Edge[] } | null) => void; + setClipboard: ( + clipboard: { nodes: Node[]; edges: Edge[] } | null, + ) => void; setLastMousePosition: (position: { x: number; y: number } | null) => void; setShareLink: (shareLink: string) => void; setPendingExternalId: (pendingExternalId: string | null) => void; setShowCompletionNeeds: (showCompletionNeeds: boolean) => void; setShowCompletionOptional: (showCompletionOptional: boolean) => void; setShowUnlockAfter: (showUnlockAfter: boolean) => void; - + // Bulk operations loadRoadmapData: (roadmapData: RoadmapData) => void; getRoadmapData: () => RoadmapData; @@ -91,7 +104,6 @@ const initialState = { nodes: [], edges: [], settings: { background: { color: "#ffffff" } }, - saved: true, previewMode: false, debugMode: false, showGrid: false, @@ -115,218 +127,343 @@ const initialState = { }; export const useEditorStore = create()( - temporal( - (set, get) => ({ - ...initialState, - - // ReactFlow handlers - onNodesChange: (changes) => { - set({ - nodes: applyNodeChanges(changes, get().nodes), - saved: false, - }); - }, + persist( + temporal( + (set, get) => ({ + ...initialState, - onEdgesChange: (changes) => { - set({ - edges: applyEdgeChanges(changes, get().edges), - saved: false, - }); - }, + // ReactFlow handlers + onNodesChange: (changes) => { + set({ + nodes: applyNodeChanges(changes, get().nodes), + }); + }, - onConnect: (connection) => { - set({ - edges: addEdge(connection, get().edges), - saved: false, - }); - }, + onEdgesChange: (changes) => { + set({ + edges: applyEdgeChanges(changes, get().edges), + }); + }, - // Node operations - setNodes: (nodes) => { - set({ nodes, saved: false }); - }, + onConnect: (connection) => { + set({ + edges: addEdge(connection, get().edges), + }); + }, - setEdges: (edges) => { - set({ edges, saved: false }); - }, + // Node operations + setNodes: (nodes) => { + set({ nodes }); + }, - setSettings: (settings) => { - set({ settings, saved: false }); - }, + setEdges: (edges) => { + set({ edges }); + }, - updateNode: (nodeId, updates) => { - set({ - nodes: get().nodes.map((n) => - n.id === nodeId ? { ...n, ...updates } : n - ), - saved: false, - }); - }, + setSettings: (settings) => { + set({ settings }); + }, - updateNodeData: (nodeId, dataUpdates) => { - set({ - nodes: get().nodes.map((n) => - n.id === nodeId ? { ...n, data: { ...n.data, ...dataUpdates } } : n - ), - saved: false, - }); - }, + updateDebugEdges: () => { + const debugMode = get().debugMode; + const nodes = get().nodes; + const showCompletionNeeds = get().showCompletionNeeds; + const showCompletionOptional = get().showCompletionOptional; + const showUnlockAfter = get().showUnlockAfter; + // Filter out existing debug edges + const baseEdges = get().edges.filter( + (e) => !e.id.startsWith("debug-"), + ); + const newEdges: Edge[] = [...baseEdges]; - updateNodes: (updates) => { - set({ - nodes: get().nodes.map((n) => { - const updated = updates.find((un) => un.id === n.id); - return updated ? updated : n; - }), - saved: false, - }); - }, + if (debugMode) { + nodes.forEach((node) => { + if ( + showCompletionNeeds && + node.type === "topic" && + node.data?.completion?.needs + ) { + node.data.completion.needs.forEach((needId: string) => { + const edgeId = `debug-edge-${needId}-to-${node.id}`; + newEdges.push({ + id: edgeId, + target: needId, + source: node.id, + animated: true, + style: { + stroke: "#f97316", + strokeWidth: 2, + strokeDasharray: "5,5", + }, + type: "floating", + }); + }); + } + if (showCompletionOptional && node.data?.completion?.optional) { + node.data.completion.optional.forEach((optionalId: string) => { + const edgeId = `debug-edge-optional-${optionalId}-to-${node.id}`; + newEdges.push({ + id: edgeId, + target: optionalId, + source: node.id, + animated: true, + style: { + stroke: "#eab308", + strokeWidth: 2, + strokeDasharray: "5,5", + }, + type: "floating", + }); + }); + } + }); + nodes.forEach((node) => { + if (showUnlockAfter && node.data.unlock?.after) { + node.data.unlock.after.forEach((unlockId: string) => { + const edgeId = `debug-edge-${unlockId}-to-${node.id}`; + newEdges.push({ + id: edgeId, + target: unlockId, + source: node.id, + animated: true, + style: { + stroke: "#10b981", + strokeWidth: 2, + strokeDasharray: "5,5", + }, + type: "floating", + }); + }); + } + }); + } + set({ edges: newEdges }); + }, - updateEdge: (edgeId, updates) => { - set({ - edges: get().edges.map((e) => - e.id === edgeId ? { ...e, ...updates } : e - ), - saved: false, - }); - // Update selected edge if it's the one being updated - const selectedEdge = get().selectedEdge; - if (selectedEdge && selectedEdge.id === edgeId) { - set({ selectedEdge: { ...selectedEdge, ...updates } }); - } - }, + updateNode: (nodeId, updates) => { + set({ + nodes: get().nodes.map((n) => + n.id === nodeId ? { ...n, ...updates } : n, + ), + }); + }, - deleteNode: (nodeId) => { - set({ - nodes: get().nodes.filter((n) => n.id !== nodeId), - edges: get().edges.filter((e) => e.source !== nodeId && e.target !== nodeId), - saved: false, - }); - }, + updateNodeData: (nodeId, dataUpdates) => { + set({ + nodes: get().nodes.map((n) => + n.id === nodeId + ? { ...n, data: { ...n.data, ...dataUpdates } } + : n, + ), + }); + }, - deleteEdge: (edgeId) => { - set({ - edges: get().edges.filter((e) => e.id !== edgeId), - saved: false, - }); - }, + updateNodes: (updates) => { + set({ + nodes: get().nodes.map((n) => { + const updated = updates.find((un) => un.id === n.id); + return updated ? updated : n; + }), + }); + }, - addNode: (node) => { - set({ - nodes: [...get().nodes, node], - saved: false, - }); - }, + updateEdge: (edgeId, updates) => { + set({ + edges: get().edges.map((e) => + e.id === edgeId ? { ...e, ...updates } : e, + ), + }); + // Update selected edge if it's the one being updated + const selectedEdge = get().selectedEdge; + if (selectedEdge && selectedEdge.id === edgeId) { + set({ selectedEdge: { ...selectedEdge, ...updates } }); + } + }, - // UI state setters - setSaved: (saved) => set({ saved }), - setPreviewMode: (previewMode) => set({ previewMode }), - setDebugMode: (debugMode) => set({ debugMode }), - setShowGrid: (showGrid) => set({ showGrid }), - setHelpOpen: (helpOpen) => set({ helpOpen }), - setDrawerOpen: (drawerOpen) => set({ drawerOpen }), - setSettingsDrawerOpen: (settingsDrawerOpen) => set({ settingsDrawerOpen }), - setEdgeDrawerOpen: (edgeDrawerOpen) => set({ edgeDrawerOpen }), - setShareDialogOpen: (shareDialogOpen) => set({ shareDialogOpen }), - setLoadExternalDialogOpen: (loadExternalDialogOpen) => set({ loadExternalDialogOpen }), - setSelectedNodeId: (selectedNodeId) => set({ selectedNodeId }), - setSelectedNodeIds: (selectedNodeIds) => set({ selectedNodeIds }), - setSelectedEdge: (selectedEdge) => set({ selectedEdge }), - setNextNodeId: (nextNodeId) => set({ nextNodeId }), - setClipboard: (clipboard) => set({ clipboard }), - setLastMousePosition: (lastMousePosition) => set({ lastMousePosition }), - setShareLink: (shareLink) => set({ shareLink }), - setPendingExternalId: (pendingExternalId) => set({ pendingExternalId }), - setShowCompletionNeeds: (showCompletionNeeds) => set({ showCompletionNeeds }), - setShowCompletionOptional: (showCompletionOptional) => set({ showCompletionOptional }), - setShowUnlockAfter: (showUnlockAfter) => set({ showUnlockAfter }), - - // Bulk operations - loadRoadmapData: (roadmapData) => { - const nodesArr = Array.isArray(roadmapData?.nodes) ? roadmapData.nodes : []; - const edgesArr = Array.isArray(roadmapData?.edges) ? roadmapData.edges : []; - - const rawNodes = nodesArr.map((n) => ({ - ...n, - draggable: true, - className: n.data.color ? n.data.color : n.className, - data: { ...n.data }, - })); - - // Calculate next node ID - let nextNodeId = 1; - if (nodesArr.length > 0) { - const maxId = Math.max( - ...nodesArr - .map((n) => parseInt(n.id.replace(/\D/g, ""), 10)) - .filter((id) => !isNaN(id)) - ); - nextNodeId = maxId + 1; - } - - set({ - nodes: rawNodes, - edges: edgesArr, - settings: roadmapData?.settings || { background: { color: "#ffffff" } }, - nextNodeId, - }); - }, + deleteNode: (nodeId) => { + set({ + nodes: get().nodes.filter((n) => n.id !== nodeId), + edges: get().edges.filter( + (e) => e.source !== nodeId && e.target !== nodeId, + ), + }); + }, + + deleteEdge: (edgeId) => { + set({ + edges: get().edges.filter((e) => e.id !== edgeId), + }); + }, + + addNode: (node) => { + set({ + nodes: [...get().nodes, node], + }); + }, - getRoadmapData: () => { - const state = get(); - return { - nodes: state.nodes.map((n) => ({ - id: n.id, - type: n.type, - position: n.position, - width: n.width, - height: n.height, - zIndex: n.zIndex, - data: n.data, - })), - edges: state.edges - .filter((e) => !e.id.startsWith("debug-")) - .map((e) => ({ - id: e.id, - source: e.source, - target: e.target, - sourceHandle: e.sourceHandle, - targetHandle: e.targetHandle, - animated: e.animated, - type: e.type, - style: e.style, + // UI state setters + setPreviewMode: (previewMode) => set({ previewMode }), + setDebugMode: (debugMode) => { + get().updateDebugEdges(); + set({ debugMode }); + }, + setShowGrid: (showGrid) => set({ showGrid }), + setHelpOpen: (helpOpen) => set({ helpOpen }), + setDrawerOpen: (drawerOpen) => set({ drawerOpen }), + setSettingsDrawerOpen: (settingsDrawerOpen) => + set({ settingsDrawerOpen }), + setEdgeDrawerOpen: (edgeDrawerOpen) => set({ edgeDrawerOpen }), + setShareDialogOpen: (shareDialogOpen) => set({ shareDialogOpen }), + setLoadExternalDialogOpen: (loadExternalDialogOpen) => + set({ loadExternalDialogOpen }), + setSelectedNodeId: (selectedNodeId) => + set({ + selectedNodeId, + nodes: get().nodes.map((n) => ({ + ...n, + selected: n.id === selectedNodeId, })), - settings: state.settings, - version: 1, - }; - }, + }), + setSelectedNodeIds: (selectedNodeIds) => + set({ + selectedNodeIds, + nodes: get().nodes.map((n) => ({ + ...n, + selected: selectedNodeIds.includes(n.id), + })), + }), + setSelectedEdge: (selectedEdge) => set({ selectedEdge }), + setNextNodeId: (nextNodeId) => set({ nextNodeId }), + setClipboard: (clipboard) => set({ clipboard }), + setLastMousePosition: (lastMousePosition) => set({ lastMousePosition }), + setShareLink: (shareLink) => set({ shareLink }), + setPendingExternalId: (pendingExternalId) => set({ pendingExternalId }), + setShowCompletionNeeds: (showCompletionNeeds) => { + get().updateDebugEdges(); + set({ showCompletionNeeds }); + }, + setShowCompletionOptional: (showCompletionOptional) => { + get().updateDebugEdges(); + set({ showCompletionOptional }); + }, + setShowUnlockAfter: (showUnlockAfter) => { + get().updateDebugEdges(); + set({ showUnlockAfter }); + }, - closeAllDrawers: () => { - set({ - drawerOpen: false, - selectedNodeId: null, - edgeDrawerOpen: false, - selectedEdge: null, - settingsDrawerOpen: false, - }); - }, + // Bulk operations + loadRoadmapData: (roadmapData) => { + const nodesArr = Array.isArray(roadmapData?.nodes) + ? roadmapData.nodes + : []; + const edgesArr = Array.isArray(roadmapData?.edges) + ? roadmapData.edges + : []; - reset: () => { - set(initialState); + const rawNodes = nodesArr.map((n) => ({ + ...n, + draggable: true, + className: n.data.color ? n.data.color : n.className, + data: { ...n.data }, + })); + + // Calculate next node ID + let nextNodeId = 1; + if (nodesArr.length > 0) { + const maxId = Math.max( + ...nodesArr + .map((n) => parseInt(n.id.replace(/\D/g, ""), 10)) + .filter((id) => !isNaN(id)), + ); + nextNodeId = maxId + 1; + } + + set({ + nodes: rawNodes, + edges: edgesArr, + settings: roadmapData?.settings || { + background: { color: "#ffffff" }, + }, + nextNodeId, + }); + }, + + getRoadmapData: () => { + const state = get(); + return { + nodes: state.nodes.map((n) => ({ + id: n.id, + type: n.type, + position: n.position, + width: n.width, + height: n.height, + zIndex: n.zIndex, + data: n.data, + })), + edges: state.edges + .filter((e) => !e.id.startsWith("debug-")) + .map((e) => ({ + id: e.id, + source: e.source, + target: e.target, + sourceHandle: e.sourceHandle, + targetHandle: e.targetHandle, + animated: e.animated, + type: e.type, + style: e.style, + })), + settings: state.settings, + version: 1, + }; + }, + + closeAllDrawers: () => { + set({ + drawerOpen: false, + selectedNodeId: null, + edgeDrawerOpen: false, + selectedEdge: null, + settingsDrawerOpen: false, + }); + }, + + reset: () => { + set(initialState); + }, + }), + { + equality: (oldState, newState) => isDeepEqual(oldState, newState), + handleSet: (handleSet) => + throttle( + 1000, + (state) => { + handleSet(state); + }, + { noLeading: true, noTrailing: false }, + ), + partialize: (state): any => { + const { nodes, edges, settings } = state; + return { nodes, edges, settings }; + }, }, - }), + ), { - // Zundo options - limit: 100, - equality: (a, b) => a === b, - } - ) + name: "learningmap-data", // name of the item in storage + version: 1, + partialize: (state) => { + const { nodes, edges, settings } = state; + return { nodes, edges, settings }; + }, + }, + ), ); +type PartialEditorState = Pick; + // Hook for accessing temporal store (undo/redo) -export const useTemporalStore = ( - selector?: (state: TemporalState) => T, - equality?: (a: T, b: T) => boolean -) => { - return useStoreWithEqualityFn(useEditorStore.temporal, selector as any, equality); -}; +export function useTemporalStore( + selector?: (state: TemporalState) => T, + equality?: (a: T, b: T) => boolean, +) { + return useStoreWithEqualityFn(useEditorStore.temporal, selector!, equality); +} diff --git a/packages/learningmap/src/index.css b/packages/learningmap/src/index.css index fdee311..3f3314a 100644 --- a/packages/learningmap/src/index.css +++ b/packages/learningmap/src/index.css @@ -262,6 +262,7 @@ header.drawer-header { opacity: 0; transform: translate(-50%, -50%) scale(0.95); } + to { opacity: 1; transform: translate(-50%, -50%) scale(1); @@ -326,6 +327,7 @@ header.drawer-header { cursor: pointer; display: flex; align-items: center; + justify-content: center; gap: 6px; transition: background 0.2s; } @@ -645,6 +647,10 @@ dialog.help[open] { align-items: center; border-bottom: 1px solid #e5e7eb; + button { + width: auto; + } + h2 { margin: 0; font-size: 24px; From b543f66af33aefd893a2ac03ae2641948776f0c4 Mon Sep 17 00:00:00 2001 From: Mike Barkmin Date: Mon, 13 Oct 2025 23:38:13 +0200 Subject: [PATCH 17/17] lock --- pnpm-lock.yaml | 4850 ++++++++++++++++++++++++++---------------------- 1 file changed, 2665 insertions(+), 2185 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8b64214..d5068d4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true @@ -61,13 +61,16 @@ importers: dependencies: '@szhsin/react-menu': specifier: ^4.5.0 - version: 4.5.0(react-dom@19.2.0)(react@19.2.0) + version: 4.5.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@xyflow/react': specifier: ^12.8.6 - version: 12.8.6(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + version: 12.8.6(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) elkjs: specifier: ^0.11.0 version: 0.11.0 + fast-deep-equal: + specifier: ^3.1.3 + version: 3.1.3 html-to-image: specifier: 1.11.13 version: 1.11.13 @@ -80,15 +83,18 @@ importers: react-dom: specifier: ^19.2.0 version: 19.2.0(react@19.2.0) + throttle-debounce: + specifier: ^5.0.2 + version: 5.0.2 tslib: specifier: ^2.8.1 version: 2.8.1 zundo: specifier: ^2.3.0 - version: 2.3.0(zustand@5.0.8) + version: 2.3.0(zustand@5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0))) zustand: specifier: ^5.0.8 - version: 5.0.8(@types/react@19.2.2)(react@19.2.0) + version: 5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) devDependencies: '@types/react': specifier: ^19.2.2 @@ -96,9 +102,12 @@ importers: '@types/react-dom': specifier: ^19.2.1 version: 19.2.1(@types/react@19.2.2) + '@types/throttle-debounce': + specifier: ^5.0.2 + version: 5.0.2 vitest: specifier: ^3.0.5 - version: 3.2.4(@types/node@24.7.2) + version: 3.2.4(@types/node@24.7.2)(terser@5.44.0) packages/web-component: dependencies: @@ -107,7 +116,7 @@ importers: version: link:../learningmap '@r2wc/react-to-web-component': specifier: ^2.1.0 - version: 2.1.0(react-dom@19.2.0)(react@19.2.0) + version: 2.1.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: ^19.2.0 version: 19.2.0 @@ -120,7 +129,7 @@ importers: devDependencies: '@rollup/plugin-typescript': specifier: ^12.1.4 - version: 12.1.4(tslib@2.8.1)(typescript@5.9.3) + version: 12.1.4(rollup@4.52.4)(tslib@2.8.1)(typescript@5.9.3) '@types/react': specifier: ^19.2.2 version: 19.2.2 @@ -129,10 +138,10 @@ importers: version: 19.2.1(@types/react@19.2.2) '@vitejs/plugin-react': specifier: ^5.0.4 - version: 5.0.4(vite@7.1.9) + version: 5.0.4(vite@7.1.9(@types/node@24.7.2)(terser@5.44.0)) vite: specifier: ^7.1.9 - version: 7.1.9(@types/node@24.7.2) + version: 7.1.9(@types/node@24.7.2)(terser@5.44.0) platforms/web: dependencies: @@ -160,7 +169,7 @@ importers: version: 19.2.1(@types/react@19.2.2) '@vitejs/plugin-react': specifier: ^5.0.4 - version: 5.0.4(vite@7.1.9) + version: 5.0.4(vite@7.1.9(@types/node@24.7.2)(terser@5.44.0)) eslint: specifier: ^9.36.0 version: 9.37.0 @@ -181,735 +190,376 @@ importers: version: 8.46.0(eslint@9.37.0)(typescript@5.9.3) vite: specifier: ^7.1.9 - version: 7.1.9(@types/node@24.7.2) + version: 7.1.9(@types/node@24.7.2)(terser@5.44.0) packages: - /@babel/code-frame@7.27.1: + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.27.1 - js-tokens: 4.0.0 - picocolors: 1.1.1 - dev: true - /@babel/compat-data@7.28.4: + '@babel/compat-data@7.28.4': resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} engines: {node: '>=6.9.0'} - dev: true - /@babel/core@7.28.4: + '@babel/core@7.28.4': resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.4 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/generator@7.28.3: + '@babel/generator@7.28.3': resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - dev: true - /@babel/helper-compilation-targets@7.27.2: + '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.28.4 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.26.3 - lru-cache: 5.1.1 - semver: 6.3.1 - dev: true - /@babel/helper-globals@7.28.0: + '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-module-imports@7.27.1: + '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4): + '@babel/helper-module-transforms@7.28.3': resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/helper-plugin-utils@7.27.1: + '@babel/helper-plugin-utils@7.27.1': resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-string-parser@7.27.1: + '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-validator-identifier@7.27.1: + '@babel/helper-validator-identifier@7.27.1': resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-validator-option@7.27.1: + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helpers@7.28.4: + '@babel/helpers@7.28.4': resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 - dev: true - /@babel/parser@7.28.4: + '@babel/parser@7.28.4': resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} engines: {node: '>=6.0.0'} hasBin: true - dependencies: - '@babel/types': 7.28.4 - dev: true - /@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4): + '@babel/plugin-transform-react-jsx-self@7.27.1': resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4): + '@babel/plugin-transform-react-jsx-source@7.27.1': resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/runtime@7.28.4: + '@babel/runtime@7.28.4': resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} - dev: true - /@babel/template@7.27.2: + '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - dev: true - /@babel/traverse@7.28.4: + '@babel/traverse@7.28.4': resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.4 - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/types@7.28.4: + '@babel/types@7.28.4': resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - dev: true - /@changesets/apply-release-plan@7.0.13: + '@changesets/apply-release-plan@7.0.13': resolution: {integrity: sha512-BIW7bofD2yAWoE8H4V40FikC+1nNFEKBisMECccS16W1rt6qqhNTBDmIw5HaqmMgtLNz9e7oiALiEUuKrQ4oHg==} - dependencies: - '@changesets/config': 3.1.1 - '@changesets/get-version-range-type': 0.4.0 - '@changesets/git': 3.0.4 - '@changesets/should-skip-package': 0.1.2 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - detect-indent: 6.1.0 - fs-extra: 7.0.1 - lodash.startcase: 4.4.0 - outdent: 0.5.0 - prettier: 2.8.8 - resolve-from: 5.0.0 - semver: 7.7.3 - dev: true - /@changesets/assemble-release-plan@6.0.9: + '@changesets/assemble-release-plan@6.0.9': resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==} - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.1.3 - '@changesets/should-skip-package': 0.1.2 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - semver: 7.7.3 - dev: true - /@changesets/changelog-git@0.2.1: + '@changesets/changelog-git@0.2.1': resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} - dependencies: - '@changesets/types': 6.1.0 - dev: true - /@changesets/changelog-github@0.5.1: + '@changesets/changelog-github@0.5.1': resolution: {integrity: sha512-BVuHtF+hrhUScSoHnJwTELB4/INQxVFc+P/Qdt20BLiBFIHFJDDUaGsZw+8fQeJTRP5hJZrzpt3oZWh0G19rAQ==} - dependencies: - '@changesets/get-github-info': 0.6.0 - '@changesets/types': 6.1.0 - dotenv: 8.6.0 - transitivePeerDependencies: - - encoding - dev: true - /@changesets/cli@2.29.7(@types/node@24.7.2): + '@changesets/cli@2.29.7': resolution: {integrity: sha512-R7RqWoaksyyKXbKXBTbT4REdy22yH81mcFK6sWtqSanxUCbUi9Uf+6aqxZtDQouIqPdem2W56CdxXgsxdq7FLQ==} hasBin: true - dependencies: - '@changesets/apply-release-plan': 7.0.13 - '@changesets/assemble-release-plan': 6.0.9 - '@changesets/changelog-git': 0.2.1 - '@changesets/config': 3.1.1 - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.1.3 - '@changesets/get-release-plan': 4.0.13 - '@changesets/git': 3.0.4 - '@changesets/logger': 0.1.1 - '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.5 - '@changesets/should-skip-package': 0.1.2 - '@changesets/types': 6.1.0 - '@changesets/write': 0.4.0 - '@inquirer/external-editor': 1.0.2(@types/node@24.7.2) - '@manypkg/get-packages': 1.1.3 - ansi-colors: 4.1.3 - ci-info: 3.9.0 - enquirer: 2.4.1 - fs-extra: 7.0.1 - mri: 1.2.0 - p-limit: 2.3.0 - package-manager-detector: 0.2.11 - picocolors: 1.1.1 - resolve-from: 5.0.0 - semver: 7.7.3 - spawndamnit: 3.0.1 - term-size: 2.2.1 - transitivePeerDependencies: - - '@types/node' - dev: true - /@changesets/config@3.1.1: + '@changesets/config@3.1.1': resolution: {integrity: sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==} - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.1.3 - '@changesets/logger': 0.1.1 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - fs-extra: 7.0.1 - micromatch: 4.0.8 - dev: true - /@changesets/errors@0.2.0: + '@changesets/errors@0.2.0': resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} - dependencies: - extendable-error: 0.1.7 - dev: true - /@changesets/get-dependents-graph@2.1.3: + '@changesets/get-dependents-graph@2.1.3': resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} - dependencies: - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - picocolors: 1.1.1 - semver: 7.7.3 - dev: true - /@changesets/get-github-info@0.6.0: + '@changesets/get-github-info@0.6.0': resolution: {integrity: sha512-v/TSnFVXI8vzX9/w3DU2Ol+UlTZcu3m0kXTjTT4KlAdwSvwutcByYwyYn9hwerPWfPkT2JfpoX0KgvCEi8Q/SA==} - dependencies: - dataloader: 1.4.0 - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - dev: true - /@changesets/get-release-plan@4.0.13: + '@changesets/get-release-plan@4.0.13': resolution: {integrity: sha512-DWG1pus72FcNeXkM12tx+xtExyH/c9I1z+2aXlObH3i9YA7+WZEVaiHzHl03thpvAgWTRaH64MpfHxozfF7Dvg==} - dependencies: - '@changesets/assemble-release-plan': 6.0.9 - '@changesets/config': 3.1.1 - '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.5 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - dev: true - /@changesets/get-version-range-type@0.4.0: + '@changesets/get-version-range-type@0.4.0': resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} - dev: true - /@changesets/git@3.0.4: + '@changesets/git@3.0.4': resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} - dependencies: - '@changesets/errors': 0.2.0 - '@manypkg/get-packages': 1.1.3 - is-subdir: 1.2.0 - micromatch: 4.0.8 - spawndamnit: 3.0.1 - dev: true - /@changesets/logger@0.1.1: + '@changesets/logger@0.1.1': resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} - dependencies: - picocolors: 1.1.1 - dev: true - /@changesets/parse@0.4.1: + '@changesets/parse@0.4.1': resolution: {integrity: sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==} - dependencies: - '@changesets/types': 6.1.0 - js-yaml: 3.14.1 - dev: true - /@changesets/pre@2.0.2: + '@changesets/pre@2.0.2': resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - fs-extra: 7.0.1 - dev: true - /@changesets/read@0.6.5: + '@changesets/read@0.6.5': resolution: {integrity: sha512-UPzNGhsSjHD3Veb0xO/MwvasGe8eMyNrR/sT9gR8Q3DhOQZirgKhhXv/8hVsI0QpPjR004Z9iFxoJU6in3uGMg==} - dependencies: - '@changesets/git': 3.0.4 - '@changesets/logger': 0.1.1 - '@changesets/parse': 0.4.1 - '@changesets/types': 6.1.0 - fs-extra: 7.0.1 - p-filter: 2.1.0 - picocolors: 1.1.1 - dev: true - /@changesets/should-skip-package@0.1.2: + '@changesets/should-skip-package@0.1.2': resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} - dependencies: - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - dev: true - /@changesets/types@4.1.0: + '@changesets/types@4.1.0': resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} - dev: true - /@changesets/types@6.1.0: + '@changesets/types@6.1.0': resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} - dev: true - /@changesets/write@0.4.0: + '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} - dependencies: - '@changesets/types': 6.1.0 - fs-extra: 7.0.1 - human-id: 4.1.2 - prettier: 2.8.8 - dev: true - /@cspotcode/source-map-support@0.8.1: + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - dev: true - /@epic-web/invariant@1.0.0: + '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} - dev: true - /@esbuild/aix-ppc64@0.25.10: + '@esbuild/aix-ppc64@0.25.10': resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-arm64@0.25.10: + '@esbuild/android-arm64@0.25.10': resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-arm@0.25.10: + '@esbuild/android-arm@0.25.10': resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} engines: {node: '>=18'} cpu: [arm] os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-x64@0.25.10: + '@esbuild/android-x64@0.25.10': resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} engines: {node: '>=18'} cpu: [x64] os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-arm64@0.25.10: + '@esbuild/darwin-arm64@0.25.10': resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-x64@0.25.10: + '@esbuild/darwin-x64@0.25.10': resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-arm64@0.25.10: + '@esbuild/freebsd-arm64@0.25.10': resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-x64@0.25.10: + '@esbuild/freebsd-x64@0.25.10': resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm64@0.25.10: + '@esbuild/linux-arm64@0.25.10': resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm@0.25.10: + '@esbuild/linux-arm@0.25.10': resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} engines: {node: '>=18'} cpu: [arm] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ia32@0.25.10: + '@esbuild/linux-ia32@0.25.10': resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-loong64@0.25.10: + '@esbuild/linux-loong64@0.25.10': resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-mips64el@0.25.10: + '@esbuild/linux-mips64el@0.25.10': resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ppc64@0.25.10: + '@esbuild/linux-ppc64@0.25.10': resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-riscv64@0.25.10: + '@esbuild/linux-riscv64@0.25.10': resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-s390x@0.25.10: + '@esbuild/linux-s390x@0.25.10': resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-x64@0.25.10: + '@esbuild/linux-x64@0.25.10': resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/netbsd-arm64@0.25.10: + '@esbuild/netbsd-arm64@0.25.10': resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/netbsd-x64@0.25.10: + '@esbuild/netbsd-x64@0.25.10': resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/openbsd-arm64@0.25.10: + '@esbuild/openbsd-arm64@0.25.10': resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/openbsd-x64@0.25.10: + '@esbuild/openbsd-x64@0.25.10': resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/openharmony-arm64@0.25.10: + '@esbuild/openharmony-arm64@0.25.10': resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - requiresBuild: true - dev: true - optional: true - /@esbuild/sunos-x64@0.25.10: + '@esbuild/sunos-x64@0.25.10': resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-arm64@0.25.10: + '@esbuild/win32-arm64@0.25.10': resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-ia32@0.25.10: + '@esbuild/win32-ia32@0.25.10': resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-x64@0.25.10: + '@esbuild/win32-x64@0.25.10': resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} engines: {node: '>=18'} cpu: [x64] os: [win32] - requiresBuild: true - dev: true - optional: true - /@eslint-community/eslint-utils@4.9.0(eslint@9.37.0): + '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - dependencies: - eslint: 9.37.0 - eslint-visitor-keys: 3.4.3 - dev: true - /@eslint-community/regexpp@4.12.1: + '@eslint-community/regexpp@4.12.1': resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true - /@eslint/config-array@0.21.0: + '@eslint/config-array@0.21.0': resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@eslint/object-schema': 2.1.6 - debug: 4.4.3 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true - /@eslint/config-helpers@0.4.0: + '@eslint/config-helpers@0.4.0': resolution: {integrity: sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@eslint/core': 0.16.0 - dev: true - /@eslint/core@0.16.0: + '@eslint/core@0.16.0': resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@types/json-schema': 7.0.15 - dev: true - /@eslint/eslintrc@3.3.1: + '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - ajv: 6.12.6 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - /@eslint/js@9.37.0: + '@eslint/js@9.37.0': resolution: {integrity: sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true - /@eslint/object-schema@2.1.6: + '@eslint/object-schema@2.1.6': resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true - /@eslint/plugin-kit@0.4.0: + '@eslint/plugin-kit@0.4.0': resolution: {integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@eslint/core': 0.16.0 - levn: 0.4.1 - dev: true - /@humanfs/core@0.19.1: + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} - dev: true - /@humanfs/node@0.16.7: + '@humanfs/node@0.16.7': resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} engines: {node: '>=18.18.0'} - dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.4.3 - dev: true - /@humanwhocodes/module-importer@1.0.1: + '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - dev: true - /@humanwhocodes/retry@0.4.3: + '@humanwhocodes/retry@0.4.3': resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - dev: true - /@inquirer/external-editor@1.0.2(@types/node@24.7.2): + '@inquirer/external-editor@1.0.2': resolution: {integrity: sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==} engines: {node: '>=18'} peerDependencies: @@ -917,146 +567,76 @@ packages: peerDependenciesMeta: '@types/node': optional: true - dependencies: - '@types/node': 24.7.2 - chardet: 2.1.0 - iconv-lite: 0.7.0 - dev: true - /@isaacs/balanced-match@4.0.1: + '@isaacs/balanced-match@4.0.1': resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} - dev: true - /@isaacs/brace-expansion@5.0.0: + '@isaacs/brace-expansion@5.0.0': resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} engines: {node: 20 || >=22} - dependencies: - '@isaacs/balanced-match': 4.0.1 - dev: true - /@isaacs/cliui@8.0.2: + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} - dependencies: - string-width: 5.1.2 - string-width-cjs: /string-width@4.2.3 - strip-ansi: 7.1.2 - strip-ansi-cjs: /strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: /wrap-ansi@7.0.0 - dev: true - /@jridgewell/gen-mapping@0.3.13: + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - dev: true - /@jridgewell/remapping@2.3.5: + '@jridgewell/remapping@2.3.5': resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - dev: true - /@jridgewell/resolve-uri@3.1.2: + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - dev: true - /@jridgewell/source-map@0.3.11: + '@jridgewell/source-map@0.3.11': resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - dev: true - /@jridgewell/sourcemap-codec@1.5.5: + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - dev: true - /@jridgewell/trace-mapping@0.3.31: + '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - dev: true - /@jridgewell/trace-mapping@0.3.9: + '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - dev: true - /@manypkg/find-root@1.1.0: + '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} - dependencies: - '@babel/runtime': 7.28.4 - '@types/node': 12.20.55 - find-up: 4.1.0 - fs-extra: 8.1.0 - dev: true - /@manypkg/get-packages@1.1.3: + '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - dependencies: - '@babel/runtime': 7.28.4 - '@changesets/types': 4.1.0 - '@manypkg/find-root': 1.1.0 - fs-extra: 8.1.0 - globby: 11.1.0 - read-yaml-file: 1.1.0 - dev: true - /@nodelib/fs.scandir@2.1.5: + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - dev: true - /@nodelib/fs.stat@2.0.5: + '@nodelib/fs.stat@2.0.5': resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} - dev: true - /@nodelib/fs.walk@1.2.8: + '@nodelib/fs.walk@1.2.8': resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 - dev: true - /@pkgr/core@0.2.9: + '@pkgr/core@0.2.9': resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - dev: true - /@r2wc/core@1.3.0: + '@r2wc/core@1.3.0': resolution: {integrity: sha512-aPBnND92Itl+SWWbWyyxdFFF0+RqKB6dptGHEdiPB8ZvnHWHlVzOfEvbEcyUYGtB6HBdsfkVuBiaGYyBFVTzVQ==} - dev: false - /@r2wc/react-to-web-component@2.1.0(react-dom@19.2.0)(react@19.2.0): + '@r2wc/react-to-web-component@2.1.0': resolution: {integrity: sha512-m/PzgUOEiL1HxmvfP5LgBLqB7sHeRj+d1QAeZklwS4OEI2HUU+xTpT3hhJipH5DQoFInDqDTfe0lNFFKcrqk4w==} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - dependencies: - '@r2wc/core': 1.3.0 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@rolldown/pluginutils@1.0.0-beta.38: + '@rolldown/pluginutils@1.0.0-beta.38': resolution: {integrity: sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==} - dev: true - /@rollup/plugin-typescript@12.1.4(tslib@2.8.1)(typescript@5.9.3): + '@rollup/plugin-typescript@12.1.4': resolution: {integrity: sha512-s5Hx+EtN60LMlDBvl5f04bEiFZmAepk27Q+mr85L/00zPDn1jtzlTV6FWn81MaIwqfWzKxmOJrBWHU6vtQyedQ==} engines: {node: '>=14.0.0'} peerDependencies: @@ -1068,14 +648,8 @@ packages: optional: true tslib: optional: true - dependencies: - '@rollup/pluginutils': 5.3.0 - resolve: 1.22.10 - tslib: 2.8.1 - typescript: 5.9.3 - dev: true - /@rollup/pluginutils@5.3.0: + '@rollup/pluginutils@5.3.0': resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} peerDependencies: @@ -1083,502 +657,269 @@ packages: peerDependenciesMeta: rollup: optional: true - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - dev: true - /@rollup/rollup-android-arm-eabi@4.52.4: + '@rollup/rollup-android-arm-eabi@4.52.4': resolution: {integrity: sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==} cpu: [arm] os: [android] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-android-arm64@4.52.4: + '@rollup/rollup-android-arm64@4.52.4': resolution: {integrity: sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==} cpu: [arm64] os: [android] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-darwin-arm64@4.52.4: + '@rollup/rollup-darwin-arm64@4.52.4': resolution: {integrity: sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==} cpu: [arm64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-darwin-x64@4.52.4: + '@rollup/rollup-darwin-x64@4.52.4': resolution: {integrity: sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==} cpu: [x64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-freebsd-arm64@4.52.4: + '@rollup/rollup-freebsd-arm64@4.52.4': resolution: {integrity: sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==} cpu: [arm64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-freebsd-x64@4.52.4: + '@rollup/rollup-freebsd-x64@4.52.4': resolution: {integrity: sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==} cpu: [x64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.52.4: + '@rollup/rollup-linux-arm-gnueabihf@4.52.4': resolution: {integrity: sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==} cpu: [arm] os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-arm-musleabihf@4.52.4: + '@rollup/rollup-linux-arm-musleabihf@4.52.4': resolution: {integrity: sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==} cpu: [arm] os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-arm64-gnu@4.52.4: + '@rollup/rollup-linux-arm64-gnu@4.52.4': resolution: {integrity: sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==} cpu: [arm64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-arm64-musl@4.52.4: + '@rollup/rollup-linux-arm64-musl@4.52.4': resolution: {integrity: sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==} cpu: [arm64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-loong64-gnu@4.52.4: + '@rollup/rollup-linux-loong64-gnu@4.52.4': resolution: {integrity: sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==} cpu: [loong64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-ppc64-gnu@4.52.4: + '@rollup/rollup-linux-ppc64-gnu@4.52.4': resolution: {integrity: sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==} cpu: [ppc64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-riscv64-gnu@4.52.4: + '@rollup/rollup-linux-riscv64-gnu@4.52.4': resolution: {integrity: sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==} cpu: [riscv64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-riscv64-musl@4.52.4: + '@rollup/rollup-linux-riscv64-musl@4.52.4': resolution: {integrity: sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==} cpu: [riscv64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-s390x-gnu@4.52.4: + '@rollup/rollup-linux-s390x-gnu@4.52.4': resolution: {integrity: sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==} cpu: [s390x] os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-x64-gnu@4.52.4: + '@rollup/rollup-linux-x64-gnu@4.52.4': resolution: {integrity: sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==} cpu: [x64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-linux-x64-musl@4.52.4: + '@rollup/rollup-linux-x64-musl@4.52.4': resolution: {integrity: sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==} cpu: [x64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-openharmony-arm64@4.52.4: + '@rollup/rollup-openharmony-arm64@4.52.4': resolution: {integrity: sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==} cpu: [arm64] os: [openharmony] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-win32-arm64-msvc@4.52.4: + '@rollup/rollup-win32-arm64-msvc@4.52.4': resolution: {integrity: sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==} cpu: [arm64] os: [win32] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-win32-ia32-msvc@4.52.4: + '@rollup/rollup-win32-ia32-msvc@4.52.4': resolution: {integrity: sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==} cpu: [ia32] os: [win32] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-win32-x64-gnu@4.52.4: + '@rollup/rollup-win32-x64-gnu@4.52.4': resolution: {integrity: sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==} cpu: [x64] os: [win32] - requiresBuild: true - dev: true - optional: true - /@rollup/rollup-win32-x64-msvc@4.52.4: + '@rollup/rollup-win32-x64-msvc@4.52.4': resolution: {integrity: sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==} cpu: [x64] os: [win32] - requiresBuild: true - dev: true - optional: true - /@szhsin/react-menu@4.5.0(react-dom@19.2.0)(react@19.2.0): + '@szhsin/react-menu@4.5.0': resolution: {integrity: sha512-fblZBPxFGjg+QxSbdDsWk3H8brupuQG+ayYXElwg+FdCxwLQLvrHG9K6O9+4pE8qLyDy5REn/2HmffPXcBZviA==} peerDependencies: react: '>=16.14.0' react-dom: '>=16.14.0' - dependencies: - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-transition-state: 2.3.1(react-dom@19.2.0)(react@19.2.0) - dev: false - /@tsconfig/node10@1.0.11: + '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} - dev: true - /@tsconfig/node12@1.0.11: + '@tsconfig/node12@1.0.11': resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - dev: true - /@tsconfig/node14@1.0.3: + '@tsconfig/node14@1.0.3': resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - dev: true - /@tsconfig/node16@1.0.4: + '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - dev: true - /@types/babel__core@7.20.5: + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - dev: true - /@types/babel__generator@7.27.0: + '@types/babel__generator@7.27.0': resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - dependencies: - '@babel/types': 7.28.4 - dev: true - /@types/babel__template@7.4.4: + '@types/babel__template@7.4.4': resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - dev: true - /@types/babel__traverse@7.28.0: + '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - dependencies: - '@babel/types': 7.28.4 - dev: true - /@types/chai@5.2.2: + '@types/chai@5.2.2': resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} - dependencies: - '@types/deep-eql': 4.0.2 - dev: true - /@types/d3-color@3.1.3: + '@types/d3-color@3.1.3': resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} - dev: false - /@types/d3-drag@3.0.7: + '@types/d3-drag@3.0.7': resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} - dependencies: - '@types/d3-selection': 3.0.11 - dev: false - /@types/d3-interpolate@3.0.4: + '@types/d3-interpolate@3.0.4': resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} - dependencies: - '@types/d3-color': 3.1.3 - dev: false - /@types/d3-selection@3.0.11: + '@types/d3-selection@3.0.11': resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} - dev: false - /@types/d3-transition@3.0.9: + '@types/d3-transition@3.0.9': resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} - dependencies: - '@types/d3-selection': 3.0.11 - dev: false - /@types/d3-zoom@3.0.8: + '@types/d3-zoom@3.0.8': resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} - dependencies: - '@types/d3-interpolate': 3.0.4 - '@types/d3-selection': 3.0.11 - dev: false - /@types/deep-eql@4.0.2: + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - dev: true - /@types/eslint-scope@3.7.7: + '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} - dependencies: - '@types/eslint': 9.6.1 - '@types/estree': 1.0.8 - dev: true - /@types/eslint@9.6.1: + '@types/eslint@9.6.1': resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} - dependencies: - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - dev: true - /@types/estree@1.0.8: + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - dev: true - /@types/json-schema@7.0.15: + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - dev: true - /@types/node@12.20.55: + '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - dev: true - /@types/node@24.7.2: + '@types/node@24.7.2': resolution: {integrity: sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==} - dependencies: - undici-types: 7.14.0 - dev: true - /@types/react-dom@19.2.1(@types/react@19.2.2): + '@types/react-dom@19.2.1': resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} peerDependencies: '@types/react': ^19.2.0 - dependencies: - '@types/react': 19.2.2 - dev: true - /@types/react@19.2.2: + '@types/react@19.2.2': resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==} - dependencies: - csstype: 3.1.3 - /@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.37.0)(typescript@5.9.3): + '@types/throttle-debounce@5.0.2': + resolution: {integrity: sha512-pDzSNulqooSKvSNcksnV72nk8p7gRqN8As71Sp28nov1IgmPKWbOEIwAWvBME5pPTtaXJAvG3O4oc76HlQ4kqQ==} + + '@typescript-eslint/eslint-plugin@8.46.0': resolution: {integrity: sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.46.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.46.0 - '@typescript-eslint/type-utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.46.0 - eslint: 9.37.0 - graphemer: 1.4.0 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.9.3): + '@typescript-eslint/parser@8.46.0': resolution: {integrity: sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - dependencies: - '@typescript-eslint/scope-manager': 8.46.0 - '@typescript-eslint/types': 8.46.0 - '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.46.0 - debug: 4.4.3 - eslint: 9.37.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/project-service@8.46.0(typescript@5.9.3): + '@typescript-eslint/project-service@8.46.0': resolution: {integrity: sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - dependencies: - '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) - '@typescript-eslint/types': 8.46.0 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/scope-manager@8.46.0: + '@typescript-eslint/scope-manager@8.46.0': resolution: {integrity: sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@typescript-eslint/types': 8.46.0 - '@typescript-eslint/visitor-keys': 8.46.0 - dev: true - /@typescript-eslint/tsconfig-utils@8.46.0(typescript@5.9.3): + '@typescript-eslint/tsconfig-utils@8.46.0': resolution: {integrity: sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - dependencies: - typescript: 5.9.3 - dev: true - /@typescript-eslint/type-utils@8.46.0(eslint@9.37.0)(typescript@5.9.3): + '@typescript-eslint/type-utils@8.46.0': resolution: {integrity: sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - dependencies: - '@typescript-eslint/types': 8.46.0 - '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.37.0 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/types@8.46.0: + '@typescript-eslint/types@8.46.0': resolution: {integrity: sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true - /@typescript-eslint/typescript-estree@8.46.0(typescript@5.9.3): + '@typescript-eslint/typescript-estree@8.46.0': resolution: {integrity: sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - dependencies: - '@typescript-eslint/project-service': 8.46.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) - '@typescript-eslint/types': 8.46.0 - '@typescript-eslint/visitor-keys': 8.46.0 - debug: 4.4.3 - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.3 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/utils@8.46.0(eslint@9.37.0)(typescript@5.9.3): + '@typescript-eslint/utils@8.46.0': resolution: {integrity: sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) - '@typescript-eslint/scope-manager': 8.46.0 - '@typescript-eslint/types': 8.46.0 - '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) - eslint: 9.37.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/visitor-keys@8.46.0: + '@typescript-eslint/visitor-keys@8.46.0': resolution: {integrity: sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@typescript-eslint/types': 8.46.0 - eslint-visitor-keys: 4.2.1 - dev: true - /@vitejs/plugin-react@5.0.4(vite@7.1.9): + '@vitejs/plugin-react@5.0.4': resolution: {integrity: sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - dependencies: - '@babel/core': 7.28.4 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) - '@rolldown/pluginutils': 1.0.0-beta.38 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 7.1.9(@types/node@24.7.2) - transitivePeerDependencies: - - supports-color - dev: true - /@vitest/expect@3.2.4: + '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - dependencies: - '@types/chai': 5.2.2 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - tinyrainbow: 2.0.0 - dev: true - /@vitest/mocker@3.2.4(vite@7.1.9): + '@vitest/mocker@3.2.4': resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: msw: ^2.4.9 @@ -1588,550 +929,305 @@ packages: optional: true vite: optional: true - dependencies: - '@vitest/spy': 3.2.4 - estree-walker: 3.0.3 - magic-string: 0.30.19 - vite: 7.1.9(@types/node@24.7.2) - dev: true - /@vitest/pretty-format@3.2.4: + '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - dependencies: - tinyrainbow: 2.0.0 - dev: true - /@vitest/runner@3.2.4: + '@vitest/runner@3.2.4': resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} - dependencies: - '@vitest/utils': 3.2.4 - pathe: 2.0.3 - strip-literal: 3.1.0 - dev: true - /@vitest/snapshot@3.2.4: + '@vitest/snapshot@3.2.4': resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} - dependencies: - '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.19 - pathe: 2.0.3 - dev: true - /@vitest/spy@3.2.4: + '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - dependencies: - tinyspy: 4.0.4 - dev: true - /@vitest/utils@3.2.4: + '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - dependencies: - '@vitest/pretty-format': 3.2.4 - loupe: 3.2.1 - tinyrainbow: 2.0.0 - dev: true - /@webassemblyjs/ast@1.14.1: + '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} - dependencies: - '@webassemblyjs/helper-numbers': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - dev: true - /@webassemblyjs/floating-point-hex-parser@1.13.2: + '@webassemblyjs/floating-point-hex-parser@1.13.2': resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} - dev: true - /@webassemblyjs/helper-api-error@1.13.2: + '@webassemblyjs/helper-api-error@1.13.2': resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} - dev: true - /@webassemblyjs/helper-buffer@1.14.1: + '@webassemblyjs/helper-buffer@1.14.1': resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} - dev: true - /@webassemblyjs/helper-numbers@1.13.2: + '@webassemblyjs/helper-numbers@1.13.2': resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} - dependencies: - '@webassemblyjs/floating-point-hex-parser': 1.13.2 - '@webassemblyjs/helper-api-error': 1.13.2 - '@xtuc/long': 4.2.2 - dev: true - /@webassemblyjs/helper-wasm-bytecode@1.13.2: + '@webassemblyjs/helper-wasm-bytecode@1.13.2': resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} - dev: true - /@webassemblyjs/helper-wasm-section@1.14.1: + '@webassemblyjs/helper-wasm-section@1.14.1': resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/wasm-gen': 1.14.1 - dev: true - /@webassemblyjs/ieee754@1.13.2: + '@webassemblyjs/ieee754@1.13.2': resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} - dependencies: - '@xtuc/ieee754': 1.2.0 - dev: true - /@webassemblyjs/leb128@1.13.2: + '@webassemblyjs/leb128@1.13.2': resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} - dependencies: - '@xtuc/long': 4.2.2 - dev: true - /@webassemblyjs/utf8@1.13.2: + '@webassemblyjs/utf8@1.13.2': resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} - dev: true - /@webassemblyjs/wasm-edit@1.14.1: + '@webassemblyjs/wasm-edit@1.14.1': resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/helper-wasm-section': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-opt': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - '@webassemblyjs/wast-printer': 1.14.1 - dev: true - /@webassemblyjs/wasm-gen@1.14.1: + '@webassemblyjs/wasm-gen@1.14.1': resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - dev: true - /@webassemblyjs/wasm-opt@1.14.1: + '@webassemblyjs/wasm-opt@1.14.1': resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - dev: true - /@webassemblyjs/wasm-parser@1.14.1: + '@webassemblyjs/wasm-parser@1.14.1': resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-api-error': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - dev: true - /@webassemblyjs/wast-printer@1.14.1: + '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@xtuc/long': 4.2.2 - dev: true - /@xtuc/ieee754@1.2.0: + '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} - dev: true - /@xtuc/long@4.2.2: + '@xtuc/long@4.2.2': resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} - dev: true - /@xyflow/react@12.8.6(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): + '@xyflow/react@12.8.6': resolution: {integrity: sha512-SksAm2m4ySupjChphMmzvm55djtgMDPr+eovPDdTnyGvShf73cvydfoBfWDFllooIQ4IaiUL5yfxHRwU0c37EA==} peerDependencies: react: '>=17' react-dom: '>=17' - dependencies: - '@xyflow/system': 0.0.70 - classcat: 5.0.5 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - zustand: 4.5.7(@types/react@19.2.2)(react@19.2.0) - transitivePeerDependencies: - - '@types/react' - - immer - dev: false - /@xyflow/system@0.0.70: + '@xyflow/system@0.0.70': resolution: {integrity: sha512-PpC//u9zxdjj0tfTSmZrg3+sRbTz6kop/Amky44U2Dl51sxzDTIUfXMwETOYpmr2dqICWXBIJwXL2a9QWtX2XA==} - dependencies: - '@types/d3-drag': 3.0.7 - '@types/d3-interpolate': 3.0.4 - '@types/d3-selection': 3.0.11 - '@types/d3-transition': 3.0.9 - '@types/d3-zoom': 3.0.8 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-zoom: 3.0.0 - dev: false - /acorn-import-phases@1.0.4(acorn@8.15.0): + acorn-import-phases@1.0.4: resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} engines: {node: '>=10.13.0'} peerDependencies: acorn: ^8.14.0 - dependencies: - acorn: 8.15.0 - dev: true - /acorn-jsx@5.3.2(acorn@8.15.0): + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 8.15.0 - dev: true - /acorn-walk@8.3.4: + acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} - dependencies: - acorn: 8.15.0 - dev: true - /acorn@8.15.0: + acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true - dev: true - /ajv-formats@2.1.1(ajv@8.17.1): + ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: ajv: ^8.0.0 peerDependenciesMeta: ajv: optional: true - dependencies: - ajv: 8.17.1 - dev: true - /ajv-keywords@5.1.0(ajv@8.17.1): + ajv-keywords@5.1.0: resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} peerDependencies: ajv: ^8.8.2 - dependencies: - ajv: 8.17.1 - fast-deep-equal: 3.1.3 - dev: true - /ajv@6.12.6: + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - dev: true - /ajv@8.17.1: + ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - dev: true - /ansi-colors@4.1.3: + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} - dev: true - /ansi-regex@5.0.1: + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - dev: true - /ansi-regex@6.2.2: + ansi-regex@6.2.2: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} - dev: true - /ansi-styles@4.3.0: + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - /ansi-styles@6.2.3: + ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - dev: true - /arg@4.1.3: + arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - dev: true - /argparse@1.0.10: + argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - dependencies: - sprintf-js: 1.0.3 - dev: true - /argparse@2.0.1: + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true - /array-union@2.1.0: + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - dev: true - /assertion-error@2.0.1: + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - dev: true - /balanced-match@1.0.2: + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - /baseline-browser-mapping@2.8.16: + baseline-browser-mapping@2.8.16: resolution: {integrity: sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==} hasBin: true - dev: true - /better-path-resolve@1.0.0: + better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} - dependencies: - is-windows: 1.0.2 - dev: true - /brace-expansion@1.1.12: + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - /brace-expansion@2.0.2: + brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - dependencies: - balanced-match: 1.0.2 - dev: true - /braces@3.0.3: + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - dependencies: - fill-range: 7.1.1 - dev: true - /browserslist@4.26.3: + browserslist@4.26.3: resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - dependencies: - baseline-browser-mapping: 2.8.16 - caniuse-lite: 1.0.30001750 - electron-to-chromium: 1.5.234 - node-releases: 2.0.23 - update-browserslist-db: 1.1.3(browserslist@4.26.3) - dev: true - /buffer-from@1.1.2: + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true - /cac@6.7.14: + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - dev: true - /callsites@3.1.0: + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - dev: true - /caniuse-lite@1.0.30001750: + caniuse-lite@1.0.30001750: resolution: {integrity: sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==} - dev: true - /chai@5.3.3: + chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.1 - deep-eql: 5.0.2 - loupe: 3.2.1 - pathval: 2.0.1 - dev: true - /chalk@4.1.2: + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - /chalk@5.6.2: + chalk@5.6.2: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - dev: true - /chardet@2.1.0: + chardet@2.1.0: resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==} - dev: true - /check-error@2.1.1: + check-error@2.1.1: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} - dev: true - /chokidar@4.0.3: + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} - dependencies: - readdirp: 4.1.2 - dev: true - /chrome-trace-event@1.0.4: + chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} - dev: true - /ci-info@3.9.0: + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - dev: true - /classcat@5.0.5: + classcat@5.0.5: resolution: {integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==} - dev: false - /color-convert@2.0.1: + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - /color-name@1.1.4: + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - /commander@2.20.3: + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - dev: true - /concat-map@0.0.1: + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true - /convert-source-map@2.0.0: + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true - /create-require@1.1.1: + create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - dev: true - /cross-env@10.1.0: + cross-env@10.1.0: resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==} engines: {node: '>=20'} hasBin: true - dependencies: - '@epic-web/invariant': 1.0.0 - cross-spawn: 7.0.6 - dev: true - /cross-spawn@7.0.6: + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - /csstype@3.1.3: + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - /d3-color@3.1.0: + d3-color@3.1.0: resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} engines: {node: '>=12'} - dev: false - /d3-dispatch@3.0.1: + d3-dispatch@3.0.1: resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} engines: {node: '>=12'} - dev: false - /d3-drag@3.0.0: + d3-drag@3.0.0: resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} engines: {node: '>=12'} - dependencies: - d3-dispatch: 3.0.1 - d3-selection: 3.0.0 - dev: false - /d3-ease@3.0.1: + d3-ease@3.0.1: resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} engines: {node: '>=12'} - dev: false - /d3-interpolate@3.0.1: + d3-interpolate@3.0.1: resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} engines: {node: '>=12'} - dependencies: - d3-color: 3.1.0 - dev: false - /d3-selection@3.0.0: + d3-selection@3.0.0: resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} engines: {node: '>=12'} - dev: false - /d3-timer@3.0.1: + d3-timer@3.0.1: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} - dev: false - /d3-transition@3.0.1(d3-selection@3.0.0): + d3-transition@3.0.1: resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} engines: {node: '>=12'} peerDependencies: d3-selection: 2 - 3 - dependencies: - d3-color: 3.1.0 - d3-dispatch: 3.0.1 - d3-ease: 3.0.1 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-timer: 3.0.1 - dev: false - /d3-zoom@3.0.0: + d3-zoom@3.0.0: resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} engines: {node: '>=12'} - dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) - dev: false - /dataloader@1.4.0: + dataloader@1.4.0: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} - dev: true - /debug@4.4.3: + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: @@ -2139,176 +1235,97 @@ packages: peerDependenciesMeta: supports-color: optional: true - dependencies: - ms: 2.1.3 - dev: true - /deep-eql@5.0.2: + deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} - dev: true - /deep-is@0.1.4: + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true - /detect-indent@6.1.0: + detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} - dev: true - /diff@4.0.2: + diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} - dev: true - /dir-glob@3.0.1: + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 - dev: true - /dotenv@8.6.0: + dotenv@8.6.0: resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} engines: {node: '>=10'} - dev: true - /eastasianwidth@0.2.0: + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: true - /electron-to-chromium@1.5.234: + electron-to-chromium@1.5.234: resolution: {integrity: sha512-RXfEp2x+VRYn8jbKfQlRImzoJU01kyDvVPBmG39eU2iuRVhuS6vQNocB8J0/8GrIMLnPzgz4eW6WiRnJkTuNWg==} - dev: true - /elkjs@0.11.0: + elkjs@0.11.0: resolution: {integrity: sha512-u4J8h9mwEDaYMqo0RYJpqNMFDoMK7f+pu4GjcV+N8jIC7TRdORgzkfSjTJemhqONFfH6fBI3wpysgWbhgVWIXw==} - dev: false - /emoji-regex@8.0.0: + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true - /emoji-regex@9.2.2: + emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: true - /enhanced-resolve@5.18.3: + enhanced-resolve@5.18.3: resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} engines: {node: '>=10.13.0'} - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.0 - dev: true - /enquirer@2.4.1: + enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} - dependencies: - ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - dev: true - /es-module-lexer@1.7.0: + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - dev: true - /esbuild@0.25.10: + esbuild@0.25.10: resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} engines: {node: '>=18'} hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.10 - '@esbuild/android-arm': 0.25.10 - '@esbuild/android-arm64': 0.25.10 - '@esbuild/android-x64': 0.25.10 - '@esbuild/darwin-arm64': 0.25.10 - '@esbuild/darwin-x64': 0.25.10 - '@esbuild/freebsd-arm64': 0.25.10 - '@esbuild/freebsd-x64': 0.25.10 - '@esbuild/linux-arm': 0.25.10 - '@esbuild/linux-arm64': 0.25.10 - '@esbuild/linux-ia32': 0.25.10 - '@esbuild/linux-loong64': 0.25.10 - '@esbuild/linux-mips64el': 0.25.10 - '@esbuild/linux-ppc64': 0.25.10 - '@esbuild/linux-riscv64': 0.25.10 - '@esbuild/linux-s390x': 0.25.10 - '@esbuild/linux-x64': 0.25.10 - '@esbuild/netbsd-arm64': 0.25.10 - '@esbuild/netbsd-x64': 0.25.10 - '@esbuild/openbsd-arm64': 0.25.10 - '@esbuild/openbsd-x64': 0.25.10 - '@esbuild/openharmony-arm64': 0.25.10 - '@esbuild/sunos-x64': 0.25.10 - '@esbuild/win32-arm64': 0.25.10 - '@esbuild/win32-ia32': 0.25.10 - '@esbuild/win32-x64': 0.25.10 - dev: true - /escalade@3.2.0: + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} - dev: true - /escape-string-regexp@4.0.0: + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - dev: true - /eslint-plugin-react-hooks@7.0.0(eslint@9.37.0): + eslint-plugin-react-hooks@7.0.0: resolution: {integrity: sha512-fNXaOwvKwq2+pXiRpXc825Vd63+KM4DLL40Rtlycb8m7fYpp6efrTp1sa6ZbP/Ap58K2bEKFXRmhURE+CJAQWw==} engines: {node: '>=18'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - dependencies: - '@babel/core': 7.28.4 - '@babel/parser': 7.28.4 - eslint: 9.37.0 - hermes-parser: 0.25.1 - zod: 4.1.12 - zod-validation-error: 4.0.2(zod@4.1.12) - transitivePeerDependencies: - - supports-color - dev: true - /eslint-plugin-react-refresh@0.4.23(eslint@9.37.0): + eslint-plugin-react-refresh@0.4.23: resolution: {integrity: sha512-G4j+rv0NmbIR45kni5xJOrYvCtyD3/7LjpVH8MPPcudXDcNu8gv+4ATTDXTtbRR8rTCM5HxECvCSsRmxKnWDsA==} peerDependencies: eslint: '>=8.40' - dependencies: - eslint: 9.37.0 - dev: true - /eslint-scope@5.1.1: + eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - dev: true - /eslint-scope@8.4.0: + eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - dev: true - /eslint-visitor-keys@3.4.3: + eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /eslint-visitor-keys@4.2.1: + eslint-visitor-keys@4.2.1: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true - /eslint@9.37.0: + eslint@9.37.0: resolution: {integrity: sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true @@ -2317,148 +1334,73 @@ packages: peerDependenciesMeta: jiti: optional: true - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) - '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.21.0 - '@eslint/config-helpers': 0.4.0 - '@eslint/core': 0.16.0 - '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.37.0 - '@eslint/plugin-kit': 0.4.0 - '@humanfs/node': 0.16.7 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - transitivePeerDependencies: - - supports-color - dev: true - /espree@10.4.0: + espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 4.2.1 - dev: true - /esprima@4.0.1: + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - dev: true - /esquery@1.6.0: + esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} - dependencies: - estraverse: 5.3.0 - dev: true - /esrecurse@4.3.0: + esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} - dependencies: - estraverse: 5.3.0 - dev: true - /estraverse@4.3.0: + estraverse@4.3.0: resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} engines: {node: '>=4.0'} - dev: true - /estraverse@5.3.0: + estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} - dev: true - /estree-walker@2.0.2: + estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: true - /estree-walker@3.0.3: + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - dependencies: - '@types/estree': 1.0.8 - dev: true - /esutils@2.0.3: + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - dev: true - /events@3.3.0: + events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - dev: true - /expect-type@1.2.2: + expect-type@1.2.2: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} - dev: true - /extendable-error@0.1.7: + extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} - dev: true - /fast-deep-equal@3.1.3: + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true - /fast-glob@3.3.3: + fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - dev: true - /fast-json-stable-stringify@2.1.0: + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - /fast-levenshtein@2.0.6: + fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true - /fast-uri@3.1.0: + fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - dev: true - /fastq@1.19.1: + fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} - dependencies: - reusify: 1.1.0 - dev: true - /fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} peerDependencies: @@ -2466,497 +1408,314 @@ packages: peerDependenciesMeta: picomatch: optional: true - dependencies: - picomatch: 4.0.3 - dev: true - /file-entry-cache@8.0.0: + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} - dependencies: - flat-cache: 4.0.1 - dev: true - /fill-range@7.1.1: + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - dev: true - /find-up@4.1.0: + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - dev: true - /find-up@5.0.0: + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - dev: true - /flat-cache@4.0.1: + flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - dependencies: - flatted: 3.3.3 - keyv: 4.5.4 - dev: true - /flatted@3.3.3: + flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - dev: true - /foreground-child@3.3.1: + foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - dev: true - /fs-extra@7.0.1: + fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - dev: true - /fs-extra@8.1.0: + fs-extra@8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - dev: true - /fsevents@2.3.3: + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - requiresBuild: true - dev: true - optional: true - /function-bind@1.1.2: + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: true - /gensync@1.0.0-beta.2: + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - dev: true - /glob-parent@5.1.2: + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - dev: true - /glob-parent@6.0.2: + glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - dependencies: - is-glob: 4.0.3 - dev: true - /glob-to-regexp@0.4.1: + glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - dev: true - /glob@11.0.3: + glob@11.0.3: resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} engines: {node: 20 || >=22} hasBin: true - dependencies: - foreground-child: 3.3.1 - jackspeak: 4.1.1 - minimatch: 10.0.3 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 2.0.0 - dev: true - /globals@14.0.0: + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - dev: true - /globals@16.4.0: + globals@16.4.0: resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} engines: {node: '>=18'} - dev: true - /globby@11.1.0: + globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - dev: true - /graceful-fs@4.2.11: + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true - /graphemer@1.4.0: + graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true - /has-flag@4.0.0: + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - dev: true - /hasown@2.0.2: + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - dependencies: - function-bind: 1.1.2 - dev: true - /hermes-estree@0.25.1: + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - dev: true - /hermes-parser@0.25.1: + hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - dependencies: - hermes-estree: 0.25.1 - dev: true - /html-to-image@1.11.13: + html-to-image@1.11.13: resolution: {integrity: sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg==} - dev: false - /human-id@4.1.2: + human-id@4.1.2: resolution: {integrity: sha512-v/J+4Z/1eIJovEBdlV5TYj1IR+ZiohcYGRY+qN/oC9dAfKzVT023N/Bgw37hrKCoVRBvk3bqyzpr2PP5YeTMSg==} hasBin: true - dev: true - /husky@9.1.7: + husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} hasBin: true - dev: true - /iconv-lite@0.7.0: + iconv-lite@0.7.0: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} - dependencies: - safer-buffer: 2.1.2 - dev: true - /ignore@5.3.2: + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - dev: true - /ignore@7.0.5: + ignore@7.0.5: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - dev: true - /import-fresh@3.3.1: + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: true - /imurmurhash@0.1.4: + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - dev: true - /is-core-module@2.16.1: + is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} - dependencies: - hasown: 2.0.2 - dev: true - /is-extglob@2.1.1: + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - dev: true - /is-fullwidth-code-point@3.0.0: + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - dev: true - /is-glob@4.0.3: + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: true - /is-number@7.0.0: + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - dev: true - /is-subdir@1.2.0: + is-subdir@1.2.0: resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} engines: {node: '>=4'} - dependencies: - better-path-resolve: 1.0.0 - dev: true - /is-windows@1.0.2: + is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} - dev: true - /isexe@2.0.0: + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true - /jackspeak@4.1.1: + jackspeak@4.1.1: resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} engines: {node: 20 || >=22} - dependencies: - '@isaacs/cliui': 8.0.2 - dev: true - /jest-worker@27.5.1: + jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} - dependencies: - '@types/node': 24.7.2 - merge-stream: 2.0.0 - supports-color: 8.1.1 - dev: true - /js-tokens@4.0.0: + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true - /js-tokens@9.0.1: + js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - dev: true - /js-yaml@3.14.1: + js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - dev: true - /js-yaml@4.1.0: + js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - dependencies: - argparse: 2.0.1 - dev: true - /jsesc@3.1.0: + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} hasBin: true - dev: true - /json-buffer@3.0.1: + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true - /json-parse-even-better-errors@2.3.1: + json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true - /json-schema-traverse@0.4.1: + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true - /json-schema-traverse@1.0.0: + json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: true - /json-stable-stringify-without-jsonify@1.0.1: + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true - /json5@2.2.3: + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true - dev: true - /jsonfile@4.0.0: + jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - optionalDependencies: - graceful-fs: 4.2.11 - dev: true - /keyv@4.5.4: + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - dependencies: - json-buffer: 3.0.1 - dev: true - /levn@0.4.1: + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true - /loader-runner@4.3.1: + loader-runner@4.3.1: resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} - dev: true - /locate-path@5.0.0: + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} - dependencies: - p-locate: 4.1.0 - dev: true - /locate-path@6.0.0: + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - dependencies: - p-locate: 5.0.0 - dev: true - /lodash.merge@4.6.2: + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true - /lodash.startcase@4.4.0: + lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} - dev: true - /loupe@3.2.1: + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} - dev: true - /lru-cache@11.2.2: + lru-cache@11.2.2: resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} engines: {node: 20 || >=22} - dev: true - /lru-cache@5.1.1: + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - /lucide-react@0.545.0(react@19.2.0): + lucide-react@0.545.0: resolution: {integrity: sha512-7r1/yUuflQDSt4f1bpn5ZAocyIxcTyVyBBChSVtBKn5M+392cPmI5YJMWOJKk/HUWGm5wg83chlAZtCcGbEZtw==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - dependencies: - react: 19.2.0 - dev: false - /magic-string@0.30.19: + magic-string@0.30.19: resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - dev: true - /make-error@1.3.6: + make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true - /merge-stream@2.0.0: + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true - /merge2@1.4.1: + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - dev: true - /micromatch@4.0.8: + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - dev: true - /mime-db@1.52.0: + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} - dev: true - /mime-types@2.1.35: + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} - dependencies: - mime-db: 1.52.0 - dev: true - /minimatch@10.0.3: + minimatch@10.0.3: resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} engines: {node: 20 || >=22} - dependencies: - '@isaacs/brace-expansion': 5.0.0 - dev: true - /minimatch@3.1.2: + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.12 - dev: true - /minimatch@9.0.5: + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} - dependencies: - brace-expansion: 2.0.2 - dev: true - /minipass@7.1.2: + minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - dev: true - /mri@1.2.0: + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} - dev: true - /ms@2.1.3: + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true - /nanoid@3.3.11: + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: true - /natural-compare@1.4.0: + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true - /neo-async@2.6.2: + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - dev: true - /node-fetch@2.7.0: + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} peerDependencies: @@ -2964,518 +1723,316 @@ packages: peerDependenciesMeta: encoding: optional: true - dependencies: - whatwg-url: 5.0.0 - dev: true - /node-releases@2.0.23: + node-releases@2.0.23: resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} - dev: true - /optionator@0.9.4: + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - dev: true - /outdent@0.5.0: + outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} - dev: true - /p-filter@2.1.0: + p-filter@2.1.0: resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} engines: {node: '>=8'} - dependencies: - p-map: 2.1.0 - dev: true - /p-limit@2.3.0: + p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} - dependencies: - p-try: 2.2.0 - dev: true - /p-limit@3.1.0: + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - dependencies: - yocto-queue: 0.1.0 - dev: true - /p-locate@4.1.0: + p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} - dependencies: - p-limit: 2.3.0 - dev: true - /p-locate@5.0.0: + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - dependencies: - p-limit: 3.1.0 - dev: true - /p-map@2.1.0: + p-map@2.1.0: resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} engines: {node: '>=6'} - dev: true - /p-try@2.2.0: + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - dev: true - /package-json-from-dist@1.0.1: + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - dev: true - /package-manager-detector@0.2.11: + package-manager-detector@0.2.11: resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} - dependencies: - quansync: 0.2.11 - dev: true - /parent-module@1.0.1: + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - dependencies: - callsites: 3.1.0 - dev: true - /path-exists@4.0.0: + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - dev: true - /path-key@3.1.1: + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - dev: true - /path-parse@1.0.7: + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true - /path-scurry@2.0.0: + path-scurry@2.0.0: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} - dependencies: - lru-cache: 11.2.2 - minipass: 7.1.2 - dev: true - /path-type@4.0.0: + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - dev: true - /pathe@2.0.3: + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - dev: true - /pathval@2.0.1: + pathval@2.0.1: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} - dev: true - /picocolors@1.1.1: + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - dev: true - /picomatch@2.3.1: + picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - dev: true - /picomatch@4.0.3: + picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - dev: true - /pify@4.0.1: + pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} - dev: true - /postcss@8.5.6: + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - dev: true - /prelude-ls@1.2.1: + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - dev: true - /prettier-plugin-sort-json@4.1.1(prettier@3.6.2): + prettier-plugin-sort-json@4.1.1: resolution: {integrity: sha512-uJ49wCzwJ/foKKV4tIPxqi4jFFvwUzw4oACMRG2dcmDhBKrxBv0L2wSKkAqHCmxKCvj0xcCZS4jO2kSJO/tRJw==} engines: {node: '>=18.0.0'} peerDependencies: prettier: ^3.0.0 - dependencies: - prettier: 3.6.2 - dev: true - /prettier@2.8.8: + prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} hasBin: true - dev: true - /prettier@3.6.2: + prettier@3.6.2: resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} engines: {node: '>=14'} hasBin: true - dev: true - /pretty-quick@4.2.2(prettier@3.6.2): + pretty-quick@4.2.2: resolution: {integrity: sha512-uAh96tBW1SsD34VhhDmWuEmqbpfYc/B3j++5MC/6b3Cb8Ow7NJsvKFhg0eoGu2xXX+o9RkahkTK6sUdd8E7g5w==} engines: {node: '>=14'} hasBin: true peerDependencies: prettier: ^3.0.0 - dependencies: - '@pkgr/core': 0.2.9 - ignore: 7.0.5 - mri: 1.2.0 - picocolors: 1.1.1 - picomatch: 4.0.3 - prettier: 3.6.2 - tinyexec: 0.3.2 - tslib: 2.8.1 - dev: true - /punycode@2.3.1: + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - dev: true - /quansync@0.2.11: + quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} - dev: true - /queue-microtask@1.2.3: + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true - /randombytes@2.1.0: + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - dependencies: - safe-buffer: 5.2.1 - dev: true - /react-dom@19.2.0(react@19.2.0): + react-dom@19.2.0: resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} peerDependencies: react: ^19.2.0 - dependencies: - react: 19.2.0 - scheduler: 0.27.0 - dev: false - /react-refresh@0.17.0: + react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} - dev: true - /react-transition-state@2.3.1(react-dom@19.2.0)(react@19.2.0): + react-transition-state@2.3.1: resolution: {integrity: sha512-Z48el73x+7HUEM131dof9YpcQ5IlM4xB+pKWH/lX3FhxGfQaNTZa16zb7pWkC/y5btTZzXfCtglIJEGc57giOw==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' - dependencies: - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /react@19.2.0: + react@19.2.0: resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} engines: {node: '>=0.10.0'} - dev: false - /read-yaml-file@1.1.0: + read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} - dependencies: - graceful-fs: 4.2.11 - js-yaml: 3.14.1 - pify: 4.0.1 - strip-bom: 3.0.0 - dev: true - /readdirp@4.1.2: + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} - dev: true - /require-from-string@2.0.2: + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - dev: true - /resolve-from@4.0.0: + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - dev: true - /resolve-from@5.0.0: + resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - dev: true - /resolve@1.22.10: + resolve@1.22.10: resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} engines: {node: '>= 0.4'} hasBin: true - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true - /reusify@1.1.0: + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true - /rimraf@6.0.1: + rimraf@6.0.1: resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} engines: {node: 20 || >=22} hasBin: true - dependencies: - glob: 11.0.3 - package-json-from-dist: 1.0.1 - dev: true - /rollup@4.52.4: + rollup@4.52.4: resolution: {integrity: sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.4 - '@rollup/rollup-android-arm64': 4.52.4 - '@rollup/rollup-darwin-arm64': 4.52.4 - '@rollup/rollup-darwin-x64': 4.52.4 - '@rollup/rollup-freebsd-arm64': 4.52.4 - '@rollup/rollup-freebsd-x64': 4.52.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.4 - '@rollup/rollup-linux-arm-musleabihf': 4.52.4 - '@rollup/rollup-linux-arm64-gnu': 4.52.4 - '@rollup/rollup-linux-arm64-musl': 4.52.4 - '@rollup/rollup-linux-loong64-gnu': 4.52.4 - '@rollup/rollup-linux-ppc64-gnu': 4.52.4 - '@rollup/rollup-linux-riscv64-gnu': 4.52.4 - '@rollup/rollup-linux-riscv64-musl': 4.52.4 - '@rollup/rollup-linux-s390x-gnu': 4.52.4 - '@rollup/rollup-linux-x64-gnu': 4.52.4 - '@rollup/rollup-linux-x64-musl': 4.52.4 - '@rollup/rollup-openharmony-arm64': 4.52.4 - '@rollup/rollup-win32-arm64-msvc': 4.52.4 - '@rollup/rollup-win32-ia32-msvc': 4.52.4 - '@rollup/rollup-win32-x64-gnu': 4.52.4 - '@rollup/rollup-win32-x64-msvc': 4.52.4 - fsevents: 2.3.3 - dev: true - /run-parallel@1.2.0: + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - dependencies: - queue-microtask: 1.2.3 - dev: true - /safe-buffer@5.2.1: + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true - /safer-buffer@2.1.2: + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: true - /scheduler@0.27.0: + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - dev: false - /schema-utils@4.3.3: + schema-utils@4.3.3: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} - dependencies: - '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) - dev: true - /semver@6.3.1: + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - dev: true - /semver@7.7.3: + semver@7.7.3: resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} hasBin: true - dev: true - /serialize-javascript@6.0.2: + serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - dependencies: - randombytes: 2.1.0 - dev: true - /shebang-command@2.0.0: + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 - dev: true - /shebang-regex@3.0.0: + shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - dev: true - /siginfo@2.0.0: + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - dev: true - /signal-exit@4.1.0: + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - dev: true - /slash@3.0.0: + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - dev: true - /source-map-js@1.2.1: + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - dev: true - /source-map-support@0.5.21: + source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: true - /source-map@0.6.1: + source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - dev: true - /spawndamnit@3.0.1: + spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - dev: true - /sprintf-js@1.0.3: + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: true - /stackback@0.0.2: + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - dev: true - /std-env@3.9.0: + std-env@3.9.0: resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} - dev: true - /string-width@4.2.3: + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - dev: true - /string-width@5.1.2: + string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.2 - dev: true - /strip-ansi@6.0.1: + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - dependencies: - ansi-regex: 5.0.1 - dev: true - /strip-ansi@7.1.2: + strip-ansi@7.1.2: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} - dependencies: - ansi-regex: 6.2.2 - dev: true - /strip-bom@3.0.0: + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - dev: true - /strip-json-comments@3.1.1: + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - dev: true - /strip-literal@3.1.0: + strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} - dependencies: - js-tokens: 9.0.1 - dev: true - /supports-color@7.2.0: + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - /supports-color@8.1.1: + supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - dependencies: - has-flag: 4.0.0 - dev: true - /supports-preserve-symlinks-flag@1.0.0: + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - dev: true - /tapable@2.3.0: + tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} - dev: true - /term-size@2.2.1: + term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} - dev: true - /terser-webpack-plugin@5.3.14(esbuild@0.25.10)(webpack@5.102.1): + terser-webpack-plugin@5.3.14: resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} engines: {node: '>= 10.13.0'} peerDependencies: @@ -3490,79 +2047,52 @@ packages: optional: true uglify-js: optional: true - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - esbuild: 0.25.10 - jest-worker: 27.5.1 - schema-utils: 4.3.3 - serialize-javascript: 6.0.2 - terser: 5.44.0 - webpack: 5.102.1(esbuild@0.25.10) - dev: true - /terser@5.44.0: + terser@5.44.0: resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==} engines: {node: '>=10'} hasBin: true - dependencies: - '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 - commander: 2.20.3 - source-map-support: 0.5.21 - dev: true - /tinybench@2.9.0: + throttle-debounce@5.0.2: + resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} + engines: {node: '>=12.22'} + + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - dev: true - /tinyexec@0.3.2: + tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - dev: true - /tinyglobby@0.2.15: + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - dev: true - /tinypool@1.1.1: + tinypool@1.1.1: resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} engines: {node: ^18.0.0 || >=20.0.0} - dev: true - /tinyrainbow@2.0.0: + tinyrainbow@2.0.0: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} - dev: true - /tinyspy@4.0.4: + tinyspy@4.0.4: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} - dev: true - /to-regex-range@5.0.1: + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - dev: true - /tr46@0.0.3: + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: true - /ts-api-utils@2.1.0(typescript@5.9.3): + ts-api-utils@2.1.0: resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' - dependencies: - typescript: 5.9.3 - dev: true - /ts-node@10.9.2(@types/node@24.7.2)(typescript@5.9.3): + ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: @@ -3575,121 +2105,56 @@ packages: optional: true '@swc/wasm': optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 24.7.2 - acorn: 8.15.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.9.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: true - /tslib@2.8.1: + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - /type-check@0.4.0: + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - dev: true - /typescript-eslint@8.46.0(eslint@9.37.0)(typescript@5.9.3): + typescript-eslint@8.46.0: resolution: {integrity: sha512-6+ZrB6y2bT2DX3K+Qd9vn7OFOJR+xSLDj+Aw/N3zBwUt27uTw2sw2TE2+UcY1RiyBZkaGbTkVg9SSdPNUG6aUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - dependencies: - '@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0)(eslint@9.37.0)(typescript@5.9.3) - '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) - eslint: 9.37.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /typescript@5.9.3: + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true - dev: true - /undici-types@7.14.0: + undici-types@7.14.0: resolution: {integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==} - dev: true - /universalify@0.1.2: + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} - dev: true - /update-browserslist-db@1.1.3(browserslist@4.26.3): + update-browserslist-db@1.1.3: resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.26.3 - escalade: 3.2.0 - picocolors: 1.1.1 - dev: true - /uri-js@4.4.1: + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - dependencies: - punycode: 2.3.1 - dev: true - /use-sync-external-store@1.6.0(react@19.2.0): + use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - dependencies: - react: 19.2.0 - dev: false - /v8-compile-cache-lib@3.0.1: + v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - dev: true - /vite-node@3.2.4(@types/node@24.7.2): + vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - dependencies: - cac: 6.7.14 - debug: 4.4.3 - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 7.1.9(@types/node@24.7.2) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - dev: true - /vite@7.1.9(@types/node@24.7.2): + vite@7.1.9: resolution: {integrity: sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -3728,19 +2193,8 @@ packages: optional: true yaml: optional: true - dependencies: - '@types/node': 24.7.2 - esbuild: 0.25.10 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.52.4 - tinyglobby: 0.2.15 - optionalDependencies: - fsevents: 2.3.3 - dev: true - /vitest@3.2.4(@types/node@24.7.2): + vitest@3.2.4: resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true @@ -3767,69 +2221,23 @@ packages: optional: true jsdom: optional: true - dependencies: - '@types/chai': 5.2.2 - '@types/node': 24.7.2 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.9) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - debug: 4.4.3 - expect-type: 1.2.2 - magic-string: 0.30.19 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.9.0 - tinybench: 2.9.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 7.1.9(@types/node@24.7.2) - vite-node: 3.2.4(@types/node@24.7.2) - why-is-node-running: 2.3.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - dev: true - /walkdir@0.4.1: + walkdir@0.4.1: resolution: {integrity: sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==} engines: {node: '>=6.0.0'} - dev: true - /watchpack@2.4.4: + watchpack@2.4.4: resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} engines: {node: '>=10.13.0'} - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - dev: true - /webidl-conversions@3.0.1: + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: true - /webpack-sources@3.3.3: + webpack-sources@3.3.3: resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} engines: {node: '>=10.13.0'} - dev: true - /webpack@5.102.1(esbuild@0.25.10): + webpack@5.102.1: resolution: {integrity: sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==} engines: {node: '>=10.13.0'} hasBin: true @@ -3838,121 +2246,58 @@ packages: peerDependenciesMeta: webpack-cli: optional: true - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - acorn-import-phases: 1.0.4(acorn@8.15.0) - browserslist: 4.26.3 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.3 - es-module-lexer: 1.7.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.1 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(esbuild@0.25.10)(webpack@5.102.1) - watchpack: 2.4.4 - webpack-sources: 3.3.3 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - dev: true - /whatwg-url@5.0.0: + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - dev: true - /which@2.0.2: + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true - dependencies: - isexe: 2.0.0 - dev: true - /why-is-node-running@2.3.0: + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} hasBin: true - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - dev: true - /word-wrap@1.2.5: + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - dev: true - /wrap-ansi@7.0.0: + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: true - /wrap-ansi@8.1.0: + wrap-ansi@8.1.0: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} - dependencies: - ansi-styles: 6.2.3 - string-width: 5.1.2 - strip-ansi: 7.1.2 - dev: true - /yallist@3.1.1: + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true - /yn@3.1.1: + yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} - dev: true - /yocto-queue@0.1.0: + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - dev: true - /zod-validation-error@4.0.2(zod@4.1.12): + zod-validation-error@4.0.2: resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} engines: {node: '>=18.0.0'} peerDependencies: zod: ^3.25.0 || ^4.0.0 - dependencies: - zod: 4.1.12 - dev: true - /zod@4.1.12: + zod@4.1.12: resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} - dev: true - /zundo@2.3.0(zustand@5.0.8): + zundo@2.3.0: resolution: {integrity: sha512-4GXYxXA17SIKYhVbWHdSEU04P697IMyVGXrC2TnzoyohEAWytFNOKqOp5gTGvaW93F/PM5Y0evbGtOPF0PWQwQ==} peerDependencies: zustand: ^4.3.0 || ^5.0.0 - dependencies: - zustand: 5.0.8(@types/react@19.2.2)(react@19.2.0) - dev: false - /zustand@4.5.7(@types/react@19.2.2)(react@19.2.0): + zustand@4.5.7: resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} engines: {node: '>=12.7.0'} peerDependencies: @@ -3966,13 +2311,8 @@ packages: optional: true react: optional: true - dependencies: - '@types/react': 19.2.2 - react: 19.2.0 - use-sync-external-store: 1.6.0(react@19.2.0) - dev: false - /zustand@5.0.8(@types/react@19.2.2)(react@19.2.0): + zustand@5.0.8: resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} engines: {node: '>=12.20.0'} peerDependencies: @@ -3989,7 +2329,2147 @@ packages: optional: true use-sync-external-store: optional: true + +snapshots: + + '@babel/code-frame@7.27.1': dependencies: - '@types/react': 19.2.2 - react: 19.2.0 - dev: false + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.4': {} + + '@babel/core@7.28.4': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.4 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.3': + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.4 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.26.3 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.4 + + '@babel/parser@7.28.4': + dependencies: + '@babel/types': 7.28.4 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/runtime@7.28.4': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + + '@babel/traverse@7.28.4': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.4 + '@babel/template': 7.27.2 + '@babel/types': 7.28.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.4': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + + '@changesets/apply-release-plan@7.0.13': + dependencies: + '@changesets/config': 3.1.1 + '@changesets/get-version-range-type': 0.4.0 + '@changesets/git': 3.0.4 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + detect-indent: 6.1.0 + fs-extra: 7.0.1 + lodash.startcase: 4.4.0 + outdent: 0.5.0 + prettier: 2.8.8 + resolve-from: 5.0.0 + semver: 7.7.3 + + '@changesets/assemble-release-plan@6.0.9': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + semver: 7.7.3 + + '@changesets/changelog-git@0.2.1': + dependencies: + '@changesets/types': 6.1.0 + + '@changesets/changelog-github@0.5.1': + dependencies: + '@changesets/get-github-info': 0.6.0 + '@changesets/types': 6.1.0 + dotenv: 8.6.0 + transitivePeerDependencies: + - encoding + + '@changesets/cli@2.29.7(@types/node@24.7.2)': + dependencies: + '@changesets/apply-release-plan': 7.0.13 + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/changelog-git': 0.2.1 + '@changesets/config': 3.1.1 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/get-release-plan': 4.0.13 + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.5 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@changesets/write': 0.4.0 + '@inquirer/external-editor': 1.0.2(@types/node@24.7.2) + '@manypkg/get-packages': 1.1.3 + ansi-colors: 4.1.3 + ci-info: 3.9.0 + enquirer: 2.4.1 + fs-extra: 7.0.1 + mri: 1.2.0 + p-limit: 2.3.0 + package-manager-detector: 0.2.11 + picocolors: 1.1.1 + resolve-from: 5.0.0 + semver: 7.7.3 + spawndamnit: 3.0.1 + term-size: 2.2.1 + transitivePeerDependencies: + - '@types/node' + + '@changesets/config@3.1.1': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/logger': 0.1.1 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + micromatch: 4.0.8 + + '@changesets/errors@0.2.0': + dependencies: + extendable-error: 0.1.7 + + '@changesets/get-dependents-graph@2.1.3': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + picocolors: 1.1.1 + semver: 7.7.3 + + '@changesets/get-github-info@0.6.0': + dependencies: + dataloader: 1.4.0 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + '@changesets/get-release-plan@4.0.13': + dependencies: + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/config': 3.1.1 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.5 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/get-version-range-type@0.4.0': {} + + '@changesets/git@3.0.4': + dependencies: + '@changesets/errors': 0.2.0 + '@manypkg/get-packages': 1.1.3 + is-subdir: 1.2.0 + micromatch: 4.0.8 + spawndamnit: 3.0.1 + + '@changesets/logger@0.1.1': + dependencies: + picocolors: 1.1.1 + + '@changesets/parse@0.4.1': + dependencies: + '@changesets/types': 6.1.0 + js-yaml: 3.14.1 + + '@changesets/pre@2.0.2': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + + '@changesets/read@0.6.5': + dependencies: + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/parse': 0.4.1 + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + p-filter: 2.1.0 + picocolors: 1.1.1 + + '@changesets/should-skip-package@0.1.2': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/types@4.1.0': {} + + '@changesets/types@6.1.0': {} + + '@changesets/write@0.4.0': + dependencies: + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + human-id: 4.1.2 + prettier: 2.8.8 + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@epic-web/invariant@1.0.0': {} + + '@esbuild/aix-ppc64@0.25.10': + optional: true + + '@esbuild/android-arm64@0.25.10': + optional: true + + '@esbuild/android-arm@0.25.10': + optional: true + + '@esbuild/android-x64@0.25.10': + optional: true + + '@esbuild/darwin-arm64@0.25.10': + optional: true + + '@esbuild/darwin-x64@0.25.10': + optional: true + + '@esbuild/freebsd-arm64@0.25.10': + optional: true + + '@esbuild/freebsd-x64@0.25.10': + optional: true + + '@esbuild/linux-arm64@0.25.10': + optional: true + + '@esbuild/linux-arm@0.25.10': + optional: true + + '@esbuild/linux-ia32@0.25.10': + optional: true + + '@esbuild/linux-loong64@0.25.10': + optional: true + + '@esbuild/linux-mips64el@0.25.10': + optional: true + + '@esbuild/linux-ppc64@0.25.10': + optional: true + + '@esbuild/linux-riscv64@0.25.10': + optional: true + + '@esbuild/linux-s390x@0.25.10': + optional: true + + '@esbuild/linux-x64@0.25.10': + optional: true + + '@esbuild/netbsd-arm64@0.25.10': + optional: true + + '@esbuild/netbsd-x64@0.25.10': + optional: true + + '@esbuild/openbsd-arm64@0.25.10': + optional: true + + '@esbuild/openbsd-x64@0.25.10': + optional: true + + '@esbuild/openharmony-arm64@0.25.10': + optional: true + + '@esbuild/sunos-x64@0.25.10': + optional: true + + '@esbuild/win32-arm64@0.25.10': + optional: true + + '@esbuild/win32-ia32@0.25.10': + optional: true + + '@esbuild/win32-x64@0.25.10': + optional: true + + '@eslint-community/eslint-utils@4.9.0(eslint@9.37.0)': + dependencies: + eslint: 9.37.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.21.0': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.0': + dependencies: + '@eslint/core': 0.16.0 + + '@eslint/core@0.16.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.37.0': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.4.0': + dependencies: + '@eslint/core': 0.16.0 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@inquirer/external-editor@1.0.2(@types/node@24.7.2)': + dependencies: + chardet: 2.1.0 + iconv-lite: 0.7.0 + optionalDependencies: + '@types/node': 24.7.2 + + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.2 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@manypkg/find-root@1.1.0': + dependencies: + '@babel/runtime': 7.28.4 + '@types/node': 12.20.55 + find-up: 4.1.0 + fs-extra: 8.1.0 + + '@manypkg/get-packages@1.1.3': + dependencies: + '@babel/runtime': 7.28.4 + '@changesets/types': 4.1.0 + '@manypkg/find-root': 1.1.0 + fs-extra: 8.1.0 + globby: 11.1.0 + read-yaml-file: 1.1.0 + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@pkgr/core@0.2.9': {} + + '@r2wc/core@1.3.0': {} + + '@r2wc/react-to-web-component@2.1.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@r2wc/core': 1.3.0 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rolldown/pluginutils@1.0.0-beta.38': {} + + '@rollup/plugin-typescript@12.1.4(rollup@4.52.4)(tslib@2.8.1)(typescript@5.9.3)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.52.4) + resolve: 1.22.10 + typescript: 5.9.3 + optionalDependencies: + rollup: 4.52.4 + tslib: 2.8.1 + + '@rollup/pluginutils@5.3.0(rollup@4.52.4)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.52.4 + + '@rollup/rollup-android-arm-eabi@4.52.4': + optional: true + + '@rollup/rollup-android-arm64@4.52.4': + optional: true + + '@rollup/rollup-darwin-arm64@4.52.4': + optional: true + + '@rollup/rollup-darwin-x64@4.52.4': + optional: true + + '@rollup/rollup-freebsd-arm64@4.52.4': + optional: true + + '@rollup/rollup-freebsd-x64@4.52.4': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.52.4': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.52.4': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.52.4': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.52.4': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.52.4': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.52.4': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.52.4': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.52.4': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.52.4': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.52.4': + optional: true + + '@rollup/rollup-linux-x64-musl@4.52.4': + optional: true + + '@rollup/rollup-openharmony-arm64@4.52.4': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.52.4': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.52.4': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.52.4': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.52.4': + optional: true + + '@szhsin/react-menu@4.5.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-transition-state: 2.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.4 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.4 + + '@types/chai@5.2.2': + dependencies: + '@types/deep-eql': 4.0.2 + + '@types/d3-color@3.1.3': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/deep-eql@4.0.2': {} + + '@types/eslint-scope@3.7.7': + dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.8 + + '@types/eslint@9.6.1': + dependencies: + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + + '@types/estree@1.0.8': {} + + '@types/json-schema@7.0.15': {} + + '@types/node@12.20.55': {} + + '@types/node@24.7.2': + dependencies: + undici-types: 7.14.0 + + '@types/react-dom@19.2.1(@types/react@19.2.2)': + dependencies: + '@types/react': 19.2.2 + + '@types/react@19.2.2': + dependencies: + csstype: 3.1.3 + + '@types/throttle-debounce@5.0.2': {} + + '@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.9.3))(eslint@9.37.0)(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/type-utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.0 + eslint: 9.37.0 + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.0 + debug: 4.4.3 + eslint: 9.37.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.46.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) + '@typescript-eslint/types': 8.46.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.46.0': + dependencies: + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/visitor-keys': 8.46.0 + + '@typescript-eslint/tsconfig-utils@8.46.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.46.0(eslint@9.37.0)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.37.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.46.0': {} + + '@typescript-eslint/typescript-estree@8.46.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.46.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.46.0(typescript@5.9.3) + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/visitor-keys': 8.46.0 + debug: 4.4.3 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.3 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.46.0(eslint@9.37.0)(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) + '@typescript-eslint/scope-manager': 8.46.0 + '@typescript-eslint/types': 8.46.0 + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + eslint: 9.37.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.46.0': + dependencies: + '@typescript-eslint/types': 8.46.0 + eslint-visitor-keys: 4.2.1 + + '@vitejs/plugin-react@5.0.4(vite@7.1.9(@types/node@24.7.2)(terser@5.44.0))': + dependencies: + '@babel/core': 7.28.4 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) + '@rolldown/pluginutils': 1.0.0-beta.38 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 7.1.9(@types/node@24.7.2)(terser@5.44.0) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@3.2.4': + dependencies: + '@types/chai': 5.2.2 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.4(vite@7.1.9(@types/node@24.7.2)(terser@5.44.0))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.19 + optionalDependencies: + vite: 7.1.9(@types/node@24.7.2)(terser@5.44.0) + + '@vitest/pretty-format@3.2.4': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.4': + dependencies: + '@vitest/utils': 3.2.4 + pathe: 2.0.3 + strip-literal: 3.1.0 + + '@vitest/snapshot@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + magic-string: 0.30.19 + pathe: 2.0.3 + + '@vitest/spy@3.2.4': + dependencies: + tinyspy: 4.0.4 + + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + + '@webassemblyjs/helper-api-error@1.13.2': {} + + '@webassemblyjs/helper-buffer@1.14.1': {} + + '@webassemblyjs/helper-numbers@1.13.2': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + + '@webassemblyjs/helper-wasm-section@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.13.2': {} + + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wasm-opt@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + + '@xyflow/react@12.8.6(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@xyflow/system': 0.0.70 + classcat: 5.0.5 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + zustand: 4.5.7(@types/react@19.2.2)(react@19.2.0) + transitivePeerDependencies: + - '@types/react' + - immer + + '@xyflow/system@0.0.70': + dependencies: + '@types/d3-drag': 3.0.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-zoom: 3.0.0 + + acorn-import-phases@1.0.4(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn-walk@8.3.4: + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ajv-formats@2.1.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + + ajv-keywords@5.1.0(ajv@8.17.1): + dependencies: + ajv: 8.17.1 + fast-deep-equal: 3.1.3 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-colors@4.1.3: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + arg@4.1.3: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + array-union@2.1.0: {} + + assertion-error@2.0.1: {} + + balanced-match@1.0.2: {} + + baseline-browser-mapping@2.8.16: {} + + better-path-resolve@1.0.0: + dependencies: + is-windows: 1.0.2 + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.26.3: + dependencies: + baseline-browser-mapping: 2.8.16 + caniuse-lite: 1.0.30001750 + electron-to-chromium: 1.5.234 + node-releases: 2.0.23 + update-browserslist-db: 1.1.3(browserslist@4.26.3) + + buffer-from@1.1.2: {} + + cac@6.7.14: {} + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001750: {} + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.6.2: {} + + chardet@2.1.0: {} + + check-error@2.1.1: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chrome-trace-event@1.0.4: {} + + ci-info@3.9.0: {} + + classcat@5.0.5: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commander@2.20.3: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + create-require@1.1.1: {} + + cross-env@10.1.0: + dependencies: + '@epic-web/invariant': 1.0.0 + cross-spawn: 7.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + d3-color@3.1.0: {} + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-ease@3.0.1: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-selection@3.0.0: {} + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + dataloader@1.4.0: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-eql@5.0.2: {} + + deep-is@0.1.4: {} + + detect-indent@6.1.0: {} + + diff@4.0.2: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dotenv@8.6.0: {} + + eastasianwidth@0.2.0: {} + + electron-to-chromium@1.5.234: {} + + elkjs@0.11.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + + es-module-lexer@1.7.0: {} + + esbuild@0.25.10: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.10 + '@esbuild/android-arm': 0.25.10 + '@esbuild/android-arm64': 0.25.10 + '@esbuild/android-x64': 0.25.10 + '@esbuild/darwin-arm64': 0.25.10 + '@esbuild/darwin-x64': 0.25.10 + '@esbuild/freebsd-arm64': 0.25.10 + '@esbuild/freebsd-x64': 0.25.10 + '@esbuild/linux-arm': 0.25.10 + '@esbuild/linux-arm64': 0.25.10 + '@esbuild/linux-ia32': 0.25.10 + '@esbuild/linux-loong64': 0.25.10 + '@esbuild/linux-mips64el': 0.25.10 + '@esbuild/linux-ppc64': 0.25.10 + '@esbuild/linux-riscv64': 0.25.10 + '@esbuild/linux-s390x': 0.25.10 + '@esbuild/linux-x64': 0.25.10 + '@esbuild/netbsd-arm64': 0.25.10 + '@esbuild/netbsd-x64': 0.25.10 + '@esbuild/openbsd-arm64': 0.25.10 + '@esbuild/openbsd-x64': 0.25.10 + '@esbuild/openharmony-arm64': 0.25.10 + '@esbuild/sunos-x64': 0.25.10 + '@esbuild/win32-arm64': 0.25.10 + '@esbuild/win32-ia32': 0.25.10 + '@esbuild/win32-x64': 0.25.10 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-plugin-react-hooks@7.0.0(eslint@9.37.0): + dependencies: + '@babel/core': 7.28.4 + '@babel/parser': 7.28.4 + eslint: 9.37.0 + hermes-parser: 0.25.1 + zod: 4.1.12 + zod-validation-error: 4.0.2(zod@4.1.12) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-refresh@0.4.23(eslint@9.37.0): + dependencies: + eslint: 9.37.0 + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.37.0: + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.0 + '@eslint/config-helpers': 0.4.0 + '@eslint/core': 0.16.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.37.0 + '@eslint/plugin-kit': 0.4.0 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esprima@4.0.1: {} + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + esutils@2.0.3: {} + + events@3.3.0: {} + + expect-type@1.2.2: {} + + extendable-error@0.1.7: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.1.0: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob-to-regexp@0.4.1: {} + + glob@11.0.3: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.1 + minimatch: 10.0.3 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + + globals@14.0.0: {} + + globals@16.4.0: {} + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-flag@4.0.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + html-to-image@1.11.13: {} + + human-id@4.1.2: {} + + husky@9.1.7: {} + + iconv-lite@0.7.0: + dependencies: + safer-buffer: 2.1.2 + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-subdir@1.2.0: + dependencies: + better-path-resolve: 1.0.0 + + is-windows@1.0.2: {} + + isexe@2.0.0: {} + + jackspeak@4.1.1: + dependencies: + '@isaacs/cliui': 8.0.2 + + jest-worker@27.5.1: + dependencies: + '@types/node': 24.7.2 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + js-tokens@4.0.0: {} + + js-tokens@9.0.1: {} + + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + loader-runner@4.3.1: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash.startcase@4.4.0: {} + + loupe@3.2.1: {} + + lru-cache@11.2.2: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.545.0(react@19.2.0): + dependencies: + react: 19.2.0 + + magic-string@0.30.19: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + make-error@1.3.6: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + minimatch@10.0.3: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minipass@7.1.2: {} + + mri@1.2.0: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + natural-compare@1.4.0: {} + + neo-async@2.6.2: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-releases@2.0.23: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + outdent@0.5.0: {} + + p-filter@2.1.0: + dependencies: + p-map: 2.1.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-map@2.1.0: {} + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + package-manager-detector@0.2.11: + dependencies: + quansync: 0.2.11 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-scurry@2.0.0: + dependencies: + lru-cache: 11.2.2 + minipass: 7.1.2 + + path-type@4.0.0: {} + + pathe@2.0.3: {} + + pathval@2.0.1: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pify@4.0.1: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-plugin-sort-json@4.1.1(prettier@3.6.2): + dependencies: + prettier: 3.6.2 + + prettier@2.8.8: {} + + prettier@3.6.2: {} + + pretty-quick@4.2.2(prettier@3.6.2): + dependencies: + '@pkgr/core': 0.2.9 + ignore: 7.0.5 + mri: 1.2.0 + picocolors: 1.1.1 + picomatch: 4.0.3 + prettier: 3.6.2 + tinyexec: 0.3.2 + tslib: 2.8.1 + + punycode@2.3.1: {} + + quansync@0.2.11: {} + + queue-microtask@1.2.3: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + react-dom@19.2.0(react@19.2.0): + dependencies: + react: 19.2.0 + scheduler: 0.27.0 + + react-refresh@0.17.0: {} + + react-transition-state@2.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + react@19.2.0: {} + + read-yaml-file@1.1.0: + dependencies: + graceful-fs: 4.2.11 + js-yaml: 3.14.1 + pify: 4.0.1 + strip-bom: 3.0.0 + + readdirp@4.1.2: {} + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + rimraf@6.0.1: + dependencies: + glob: 11.0.3 + package-json-from-dist: 1.0.1 + + rollup@4.52.4: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.52.4 + '@rollup/rollup-android-arm64': 4.52.4 + '@rollup/rollup-darwin-arm64': 4.52.4 + '@rollup/rollup-darwin-x64': 4.52.4 + '@rollup/rollup-freebsd-arm64': 4.52.4 + '@rollup/rollup-freebsd-x64': 4.52.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.4 + '@rollup/rollup-linux-arm-musleabihf': 4.52.4 + '@rollup/rollup-linux-arm64-gnu': 4.52.4 + '@rollup/rollup-linux-arm64-musl': 4.52.4 + '@rollup/rollup-linux-loong64-gnu': 4.52.4 + '@rollup/rollup-linux-ppc64-gnu': 4.52.4 + '@rollup/rollup-linux-riscv64-gnu': 4.52.4 + '@rollup/rollup-linux-riscv64-musl': 4.52.4 + '@rollup/rollup-linux-s390x-gnu': 4.52.4 + '@rollup/rollup-linux-x64-gnu': 4.52.4 + '@rollup/rollup-linux-x64-musl': 4.52.4 + '@rollup/rollup-openharmony-arm64': 4.52.4 + '@rollup/rollup-win32-arm64-msvc': 4.52.4 + '@rollup/rollup-win32-ia32-msvc': 4.52.4 + '@rollup/rollup-win32-x64-gnu': 4.52.4 + '@rollup/rollup-win32-x64-msvc': 4.52.4 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + scheduler@0.27.0: {} + + schema-utils@4.3.3: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.17.1 + ajv-formats: 2.1.1(ajv@8.17.1) + ajv-keywords: 5.1.0(ajv@8.17.1) + + semver@6.3.1: {} + + semver@7.7.3: {} + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + siginfo@2.0.0: {} + + signal-exit@4.1.0: {} + + slash@3.0.0: {} + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + spawndamnit@3.0.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + sprintf-js@1.0.3: {} + + stackback@0.0.2: {} + + std-env@3.9.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.2 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + + strip-bom@3.0.0: {} + + strip-json-comments@3.1.1: {} + + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tapable@2.3.0: {} + + term-size@2.2.1: {} + + terser-webpack-plugin@5.3.14(esbuild@0.25.10)(webpack@5.102.1(esbuild@0.25.10)): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + jest-worker: 27.5.1 + schema-utils: 4.3.3 + serialize-javascript: 6.0.2 + terser: 5.44.0 + webpack: 5.102.1(esbuild@0.25.10) + optionalDependencies: + esbuild: 0.25.10 + + terser@5.44.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + throttle-debounce@5.0.2: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinypool@1.1.1: {} + + tinyrainbow@2.0.0: {} + + tinyspy@4.0.4: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tr46@0.0.3: {} + + ts-api-utils@2.1.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + ts-node@10.9.2(@types/node@24.7.2)(typescript@5.9.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 24.7.2 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.9.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typescript-eslint@8.46.0(eslint@9.37.0)(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.9.3))(eslint@9.37.0)(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.0(eslint@9.37.0)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.46.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.0(eslint@9.37.0)(typescript@5.9.3) + eslint: 9.37.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + undici-types@7.14.0: {} + + universalify@0.1.2: {} + + update-browserslist-db@1.1.3(browserslist@4.26.3): + dependencies: + browserslist: 4.26.3 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-sync-external-store@1.6.0(react@19.2.0): + dependencies: + react: 19.2.0 + + v8-compile-cache-lib@3.0.1: {} + + vite-node@3.2.4(@types/node@24.7.2)(terser@5.44.0): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.1.9(@types/node@24.7.2)(terser@5.44.0) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite@7.1.9(@types/node@24.7.2)(terser@5.44.0): + dependencies: + esbuild: 0.25.10 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.52.4 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 24.7.2 + fsevents: 2.3.3 + terser: 5.44.0 + + vitest@3.2.4(@types/node@24.7.2)(terser@5.44.0): + dependencies: + '@types/chai': 5.2.2 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@7.1.9(@types/node@24.7.2)(terser@5.44.0)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.2.2 + magic-string: 0.30.19 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.1.9(@types/node@24.7.2)(terser@5.44.0) + vite-node: 3.2.4(@types/node@24.7.2)(terser@5.44.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 24.7.2 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + walkdir@0.4.1: {} + + watchpack@2.4.4: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + + webidl-conversions@3.0.1: {} + + webpack-sources@3.3.3: {} + + webpack@5.102.1(esbuild@0.25.10): + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.15.0 + acorn-import-phases: 1.0.4(acorn@8.15.0) + browserslist: 4.26.3 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.18.3 + es-module-lexer: 1.7.0 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.1 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.3 + tapable: 2.3.0 + terser-webpack-plugin: 5.3.14(esbuild@0.25.10)(webpack@5.102.1(esbuild@0.25.10)) + watchpack: 2.4.4 + webpack-sources: 3.3.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.1.2 + + yallist@3.1.1: {} + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} + + zod-validation-error@4.0.2(zod@4.1.12): + dependencies: + zod: 4.1.12 + + zod@4.1.12: {} + + zundo@2.3.0(zustand@5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0))): + dependencies: + zustand: 5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) + + zustand@4.5.7(@types/react@19.2.2)(react@19.2.0): + dependencies: + use-sync-external-store: 1.6.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + react: 19.2.0 + + zustand@5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)): + optionalDependencies: + '@types/react': 19.2.2 + react: 19.2.0 + use-sync-external-store: 1.6.0(react@19.2.0)