diff --git a/packages/chrome-devtools/e2e/index.spec.ts b/packages/chrome-devtools/e2e/index.spec.ts index 58e4588a16c..2defcd5355c 100644 --- a/packages/chrome-devtools/e2e/index.spec.ts +++ b/packages/chrome-devtools/e2e/index.spec.ts @@ -9,6 +9,7 @@ const beforeProxyRequest: Array = []; const afterProxyRequest: Array = []; const proxyUrl = 'http://localhost:3009/mf-manifest.json'; const mockUrl = 'http://localhost:6666/mf-manifest.json'; +const targetOrigin = 'http://localhost:3013/basic'; const sleep = (timeout: number) => new Promise((resolve) => { @@ -31,10 +32,11 @@ const afterHandler = (request: Request) => { }; test.beforeEach(async ({ context: browserContext, extensionId }) => { - const openUrl = 'http://localhost:3013/basic'; + beforeProxyRequest.length = 0; + afterProxyRequest.length = 0; targetPage = await browserContext.newPage(); targetPage.on('request', beforeHandler); - await targetPage.goto(openUrl); + await targetPage.goto(targetOrigin); devtoolsPage = await browserContext.newPage(); const extensionUrl = `chrome-extension://${extensionId}/html/main/index.html`; @@ -47,7 +49,7 @@ test.beforeEach(async ({ context: browserContext, extensionId }) => { .then((tabs) => { window.targetTab = tabs[0]; }); - }, openUrl); + }, targetOrigin); }); test('test proxy', async ({ request }) => { @@ -124,3 +126,34 @@ test('test proxy', async ({ request }) => { console.log(beforeProxyRequest, afterProxyRequest); }); + +test('open side panel via worker message', async () => { + const response = await devtoolsPage.evaluate(async (openUrl) => { + const [tab] = await chrome.tabs.query({ + url: `${openUrl}*`, + }); + return new Promise<{ + ok: boolean; + options?: { path?: string }; + message?: string; + }>((resolve) => { + chrome.runtime.sendMessage( + { + type: 'mf-devtools/open-side-panel', + tabId: tab?.id, + }, + resolve, + ); + }); + }, targetOrigin); + + if ( + !response?.ok && + response?.message?.includes('sidePanel api not available') + ) { + test.skip('Current Chromium build does not expose chrome.sidePanel'); + } + + expect(response?.ok).toBeTruthy(); + expect(response?.options?.path).toContain('html/main/index.html'); +}); diff --git a/packages/chrome-devtools/manifest.json b/packages/chrome-devtools/manifest.json index abfbdc85500..436915280ac 100644 --- a/packages/chrome-devtools/manifest.json +++ b/packages/chrome-devtools/manifest.json @@ -22,8 +22,11 @@ "matches": [""] } ], - "permissions": ["storage", "scripting"], + "permissions": ["storage", "scripting", "sidePanel"], "host_permissions": [""], + "side_panel": { + "default_path": "html/main/index.html" + }, "content_scripts": [ { "matches": [""], diff --git a/packages/chrome-devtools/mock.js b/packages/chrome-devtools/mock.js index 4c8a701dd7e..b76f2ead510 100644 --- a/packages/chrome-devtools/mock.js +++ b/packages/chrome-devtools/mock.js @@ -342,4 +342,322 @@ window.__FEDERATION__.moduleInfo = { }, }; window.__FEDERATION__.originModuleInfo = window.__FEDERATION__.moduleInfo; +window.__FEDERATION__.__SHARE__ = { + '@vmok-e2e/edenx-demo-app1:1.0.0.6867': { + default: { + 'react-dom': { + '18.3.1': { + deps: [], + useIn: ['@vmok-e2e/edenx-demo-app1'], + from: '@vmok-e2e/edenx-demo-app1', + loading: {}, + version: '18.3.1', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^18.3.1', + singleton: true, + eager: true, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + loaded: true, + lib: 'Function', + }, + }, + react: { + '18.3.1': { + deps: [], + useIn: ['@vmok-e2e/edenx-demo-app1', '@vmok-e2e/edenx-demo-app2'], + from: '@vmok-e2e/edenx-demo-app1', + loading: {}, + version: '18.3.1', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^18.3.1', + singleton: true, + eager: true, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + loaded: true, + lib: 'Function', + }, + }, + version: '0.0.6255', + axios: { + '0.24.0': { + deps: [], + useIn: [], + from: '@vmok-e2e/edenx-demo-app2', + loading: null, + version: '0.24.0', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^0.24.0', + singleton: true, + eager: false, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + }, + }, + 'react-dom/client': { + '18.3.1': { + deps: [], + useIn: [], + from: '@vmok-e2e/edenx-demo-app2', + loading: null, + version: '18.3.1', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^18.3.1', + singleton: true, + eager: false, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + }, + }, + 'react/jsx-runtime': { + '18.3.1': { + deps: [], + useIn: ['@vmok-e2e/edenx-demo-app2'], + from: '@vmok-e2e/edenx-demo-app2', + loading: {}, + version: '18.3.1', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^18.3.1', + singleton: true, + eager: false, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + loaded: true, + lib: 'Function', + }, + }, + }, + }, + '@vmok-e2e/edenx-demo-app2:1.0.0.6800': { + default: { + 'react-dom': { + '18.3.1': { + deps: [], + useIn: ['@vmok-e2e/edenx-demo-app1'], + from: '@vmok-e2e/edenx-demo-app1', + loading: {}, + version: '18.3.1', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^18.3.1', + singleton: true, + eager: true, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + loaded: true, + lib: 'Function', + }, + }, + react: { + '18.3.1': { + deps: [], + useIn: ['@vmok-e2e/edenx-demo-app1', '@vmok-e2e/edenx-demo-app2'], + from: '@vmok-e2e/edenx-demo-app1', + loading: {}, + version: '18.3.1', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^18.3.1', + singleton: true, + eager: true, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + loaded: true, + lib: 'Function', + }, + }, + version: '0.0.6255', + axios: { + '0.24.0': { + deps: [], + useIn: [], + from: '@vmok-e2e/edenx-demo-app2', + loading: null, + version: '0.24.0', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^0.24.0', + singleton: true, + eager: false, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + }, + }, + 'react-dom/client': { + '18.3.1': { + deps: [], + useIn: [], + from: '@vmok-e2e/edenx-demo-app2', + loading: null, + version: '18.3.1', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^18.3.1', + singleton: true, + eager: false, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + }, + }, + 'react/jsx-runtime': { + '18.3.1': { + deps: [], + useIn: ['@vmok-e2e/edenx-demo-app2'], + from: '@vmok-e2e/edenx-demo-app2', + loading: {}, + version: '18.3.1', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^18.3.1', + singleton: true, + eager: false, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + loaded: true, + lib: 'Function', + }, + }, + }, + }, + default: { + 'react-dom': { + '18.3.1': { + deps: [], + useIn: ['@vmok-e2e/edenx-demo-app1'], + from: '@vmok-e2e/edenx-demo-app1', + loading: {}, + version: '18.3.1', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^18.3.1', + singleton: true, + eager: true, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + loaded: true, + lib: 'Function', + }, + }, + react: { + '18.3.1': { + deps: [], + useIn: ['@vmok-e2e/edenx-demo-app1', '@vmok-e2e/edenx-demo-app2'], + from: '@vmok-e2e/edenx-demo-app1', + loading: {}, + version: '18.3.1', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^18.3.1', + singleton: true, + eager: true, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + loaded: true, + lib: 'Function', + }, + }, + version: '0.0.6255', + axios: { + '0.24.0': { + deps: [], + useIn: [], + from: '@vmok-e2e/edenx-demo-app2', + loading: null, + version: '0.24.0', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^0.24.0', + singleton: true, + eager: false, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + }, + }, + 'react-dom/client': { + '18.3.1': { + deps: [], + useIn: [], + from: '@vmok-e2e/edenx-demo-app2', + loading: null, + version: '18.3.1', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^18.3.1', + singleton: true, + eager: false, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + }, + }, + 'react/jsx-runtime': { + '18.3.1': { + deps: [], + useIn: ['@vmok-e2e/edenx-demo-app2'], + from: '@vmok-e2e/edenx-demo-app2', + loading: {}, + version: '18.3.1', + get: 'Function', + scope: ['default'], + shareConfig: { + requiredVersion: '^18.3.1', + singleton: true, + eager: false, + strictVersion: false, + layer: null, + }, + strategy: 'loaded-first', + loaded: true, + lib: 'Function', + }, + }, + }, +}; export default window.__FEDERATION__; diff --git a/packages/chrome-devtools/modern.config.ts b/packages/chrome-devtools/modern.config.ts index 4d13dcc9a50..83f41caa280 100644 --- a/packages/chrome-devtools/modern.config.ts +++ b/packages/chrome-devtools/modern.config.ts @@ -20,9 +20,8 @@ export default defineConfig({ }, tools: { webpack: (config: Record) => { - if (process.env.E2ETEST) { - config.entry.worker = './src/worker/index.ts'; - } + config.entry = config.entry || {}; + config.entry.worker = './src/worker/index.ts'; config.entry['fast-refresh'] = './src/utils/chrome/fast-refresh.ts'; config.entry['snapshot-plugin'] = './src/utils/chrome/snapshot-plugin.ts'; config.entry['post-message'] = './src/utils/chrome/post-message.ts'; diff --git a/packages/chrome-devtools/package.json b/packages/chrome-devtools/package.json index 11b91889e83..6ef6acbb117 100644 --- a/packages/chrome-devtools/package.json +++ b/packages/chrome-devtools/package.json @@ -54,13 +54,14 @@ "types": "./dist/index.d.ts" }, "dependencies": { - "@arco-design/web-react": "^2.64.1", + "@arco-design/web-react": "2.66.7", "@modern-js/runtime": "2.68.2", "@module-federation/sdk": "workspace:*", "ahooks": "^3.7.10", "dagre": "^0.8.5", - "react": "~18.3.1", - "react-dom": "~18.3.1", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "@antv/g6": "4.8.24", "reactflow": "11.11.4" }, "devDependencies": { @@ -76,8 +77,8 @@ "@types/dagre": "^0.7.52", "@types/jest": "~29.2.4", "@types/node": "~20.12.12", - "@types/react": "~18.2.0", - "@types/react-dom": "~18.3.0", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", "lint-staged": "~13.1.0", "prettier": "~3.3.3", "rimraf": "~6.0.1", diff --git a/packages/chrome-devtools/postpack.js b/packages/chrome-devtools/postpack.js index e592d14c316..e351b0d7cf2 100644 --- a/packages/chrome-devtools/postpack.js +++ b/packages/chrome-devtools/postpack.js @@ -6,9 +6,6 @@ const pkg = require(path.resolve(process.cwd(), 'package.json')); const manifest = JSON.parse( fs.readFileSync(path.resolve(process.cwd(), 'manifest.json'), 'utf8'), ); -if (!process.env.E2ETEST) { - delete manifest.background; -} pkg.version.includes('-') ? (manifest.version = '0.0.0') : (manifest.version = pkg.version); diff --git a/packages/chrome-devtools/src/App.module.scss b/packages/chrome-devtools/src/App.module.scss index b7217ade93f..3ac8f81aa0a 100644 --- a/packages/chrome-devtools/src/App.module.scss +++ b/packages/chrome-devtools/src/App.module.scss @@ -5,20 +5,319 @@ .arco-form-layout-horizontal { flex: 1; - margin: 0 1vw 0 0; + margin: 0; } .arco-form-item-wrapper { width: 100%; flex: 1; } + + .arco-empty { + color: #4b5563; + } + + .arco-select, + .arco-input { + background: transparent; + } + + .arco-tag-color-arcoblue { + background: rgba(34, 197, 94, 0.18); + border: 1px solid rgba(34, 197, 94, 0.35); + color: #4b5563; + } +} + +.shell { + width: 100%; + min-height: 100vh; + display: flex; + align-items: stretch; + justify-content: center; + gap: clamp(18px, 3vw, 36px); + padding: 28px clamp(16px, 4vw, 48px); + box-sizing: border-box; + background: radial-gradient( + circle at 10% 20%, + rgba(229, 231, 235, 0.8) 0%, + rgba(243, 244, 246, 0.9) 55% + ), + linear-gradient(135deg, #ffffff 0%, #f9fafb 40%, #f3f4f6 100%); } -.layout { +.sidebar { + width: clamp(160px, 18vw, 220px); + min-width: 150px; + display: flex; + flex-direction: column; + gap: 12px; + padding: clamp(18px, 2.5vw, 24px) clamp(14px, 2vw, 18px); + border-radius: 22px; + border: 1px solid rgba(148, 163, 184, 0.18); + background: rgba(255, 255, 255, 0.95); + box-shadow: + 0 18px 48px rgba(0, 0, 0, 0.08), + 0 1px 0 rgba(0, 0, 0, 0.05) inset; + box-sizing: border-box; +} + +.tabItem { + display: flex; + align-items: center; + justify-content: flex-start; + border: 1px solid transparent; + border-radius: 12px; + padding: 10px 12px; + background: rgba(249, 250, 251, 0.8); + color: rgba(55, 65, 81, 0.9); + font-size: 13px; + letter-spacing: 0.04em; + text-transform: uppercase; + cursor: pointer; + transition: all 0.15s ease; + white-space: nowrap; +} + +.tabItem:hover { + border-color: rgba(37, 49, 48, 0.45); + color: #1e293b; +} + +.activeTab { + border-color: rgba(99, 102, 241, 0.65); + background: linear-gradient( + 135deg, + rgba(59, 130, 246, 0.15), + rgba(37, 99, 235, 0.1) + ); + color: #1e293b; + box-shadow: 0 12px 28px rgba(30, 64, 175, 0.25); +} + +.panel { + flex: 1; + min-width: 0; width: 100%; - height: 100vh; + max-width: 1120px; + min-height: calc(100vh - 56px); + background: rgba(255, 255, 255, 0.98); + border: 1px solid rgba(0, 0, 0, 0.08); + box-shadow: + 0 24px 64px rgba(0, 0, 0, 0.06), + 0 2px 0 rgba(0, 0, 0, 0.04) inset; + border-radius: 22px; + padding: clamp(20px, 3vw, 32px); + display: flex; + flex-direction: column; + gap: 28px; + box-sizing: border-box; + color: #1f2937; +} + +.header { + display: flex; + flex-direction: column; + gap: 18px; +} + +.headerTop { + display: flex; + align-items: center; + justify-content: space-between; + gap: 14px; +} + +.branding { + display: flex; + flex-direction: column; + gap: 4px; +} + +.refresh { + :global { + .arco-btn-primary { + background: linear-gradient( + 135deg, + rgba(34, 197, 94, 0.8), + rgba(22, 163, 74, 0.7) + ); + border-color: rgba(34, 197, 94, 0.65); + } + + .arco-btn-primary:hover { + background: linear-gradient( + 135deg, + rgba(34, 197, 94, 0.95), + rgba(22, 163, 74, 0.85) + ); + } + } +} + +.logo { + font-size: 20px; + font-weight: 600; + letter-spacing: 0.02em; + color: #1e293b; +} + +.subtitle { + font-size: 12px; + font-weight: 500; + color: rgba(75, 85, 99, 0.8); + text-transform: uppercase; + letter-spacing: 0.12em; +} + +.meta { + display: flex; + align-items: stretch; + justify-content: space-between; + gap: 18px; + flex-wrap: wrap; +} + +.scope { + display: flex; + flex-direction: column; + gap: 8px; + flex: 1 1 160px; +} - & .content { - margin: 0 0.5vw 0 2vw; +.scopeLabel { + font-size: 12px; + color: rgba(75, 85, 99, 0.85); + text-transform: uppercase; + letter-spacing: 0.08em; +} + +.stats { + display: flex; + align-items: center; + gap: 14px; + flex-wrap: wrap; +} + +.statBlock { + display: flex; + flex-direction: column; + gap: 2px; + min-width: 80px; + padding: 12px 14px; + border-radius: 14px; + background: linear-gradient( + 140deg, + rgba(243, 244, 246, 0.8) 0%, + rgba(229, 231, 235, 0.6) 100% + ); + border: 1px solid rgba(203, 213, 225, 0.4); + box-shadow: 0 10px 24px rgba(0, 0, 0, 0.08); +} + +.statValue { + font-size: 22px; + font-weight: 600; + color: #1e293b; + line-height: 1.1; +} + +.statLabel { + font-size: 11px; + color: rgba(75, 85, 99, 0.88); + letter-spacing: 0.04em; + text-transform: uppercase; +} + +.body { + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; + overflow: hidden; +} + +.content { + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; + overflow: auto; + gap: 16px; +} + +@media (max-width: 980px) { + .shell { + flex-direction: column; + align-items: stretch; + } + + .sidebar { + width: 100%; + flex-direction: row; + align-items: center; + justify-content: flex-start; + overflow-x: auto; + padding: 16px 12px; + gap: 10px; + } + + .tabItem { + flex: 1 0 auto; + justify-content: center; + padding: 10px 14px; + } + + .panel { + max-width: none; + min-height: auto; + } +} + +@media (max-width: 640px) { + .panel { + padding: 20px; + } + + .meta { + gap: 12px; + } + + .stats { + width: 100%; + justify-content: space-between; } } + +.emptyState { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + border-radius: 18px; + border: 1px dashed rgba(203, 213, 225, 0.4); + background: rgba(255, 255, 255, 0.8); + padding: 32px; +} + +.empty { + :global { + .arco-empty-image > svg path { + fill: rgba(75, 85, 99, 0.5); + } + } +} + +.placeholder { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + border-radius: 18px; + border: 1px dashed rgba(203, 213, 225, 0.4); + background: rgba(255, 255, 255, 0.8); + color: rgba(75, 85, 99, 0.75); + font-size: 14px; + letter-spacing: 0.08em; + text-transform: uppercase; +} diff --git a/packages/chrome-devtools/src/App.tsx b/packages/chrome-devtools/src/App.tsx index 75e652d5c10..336fb8c5fba 100644 --- a/packages/chrome-devtools/src/App.tsx +++ b/packages/chrome-devtools/src/App.tsx @@ -1,14 +1,99 @@ -import { useState, useEffect } from 'react'; -import { Layout, Empty } from '@arco-design/web-react'; +import { useState, useEffect, useMemo, useCallback, useRef } from 'react'; +import { Empty, Tag, Button, Tooltip } from '@arco-design/web-react'; +import type { GlobalModuleInfo } from '@module-federation/sdk'; import './init'; import ProxyLayout from './component/Layout'; -import { getGlobalModuleInfo, RootComponentProps } from './utils'; +import Dependency from './component/DependencyGraph'; +import Home from './component/Home'; +import ShareGraph from './component/ShareGraph'; +import { + getGlobalModuleInfo, + refreshModuleInfo, + RootComponentProps, + separateType, + syncActiveTab, +} from './utils'; +import { MESSAGE_ACTIVE_TAB_CHANGED } from './utils/chrome/messages'; import '@arco-design/web-react/dist/css/arco.css'; import styles from './App.module.scss'; -const { Content } = Layout; +const cloneModuleInfo = (info?: GlobalModuleInfo | null): GlobalModuleInfo => { + try { + return JSON.parse(JSON.stringify(info || {})); + } catch (error) { + console.warn('[MF Devtools] cloneModuleInfo failed', error); + return (info || {}) as GlobalModuleInfo; + } +}; + +const normalizeShareValue = ( + target: any, + seen: WeakSet = new WeakSet(), +): any => { + if (typeof target === 'function') { + const name = target.name ? `: ${target.name}` : ''; + return `[Function${name}]`; + } + if (!target || typeof target !== 'object') { + return target; + } + if (seen.has(target)) { + return '[Circular]'; + } + seen.add(target); + + if (target instanceof Map) { + const mapped: Record = {}; + target.forEach((value, key) => { + mapped[String(key)] = normalizeShareValue(value, seen); + }); + return mapped; + } + + if (target instanceof Set) { + const setItems: Array = []; + target.forEach((value) => { + setItems.push(normalizeShareValue(value, seen)); + }); + return setItems; + } + + if (Array.isArray(target)) { + return target.map((item) => normalizeShareValue(item, seen)); + } + + return Object.keys(target).reduce>((memo, key) => { + memo[key] = normalizeShareValue((target as Record)[key], seen); + return memo; + }, {}); +}; + +const buildShareSnapshot = (share: any): Record => { + const normalize = (value: any) => { + try { + return normalizeShareValue(value); + } catch (error) { + console.warn('[MF Devtools] normalize share snapshot failed', error); + return normalizeShareValue(value); + } + }; + + const scopes = normalize(share || {}); + + return scopes; +}; + +const NAV_ITEMS = [ + { key: 'home', label: 'Home' }, + { key: 'proxy', label: 'Proxy' }, + { key: 'dependency', label: 'Dependency graph' }, + { key: 'share', label: 'Share graph' }, + { key: 'performance', label: 'Performance' }, +] as const; + +type TabKey = (typeof NAV_ITEMS)[number]['key']; const App = (props: RootComponentProps) => { const { @@ -20,34 +105,272 @@ const App = (props: RootComponentProps) => { customValueValidate, headerSlot, } = props; - const [module, setModule] = useState(window.__FEDERATION__?.moduleInfo || {}); - useEffect(() => { - getGlobalModuleInfo(setModule); + const [moduleInfo, setModuleInfo] = useState(() => + cloneModuleInfo( + (window.__FEDERATION__?.moduleInfo as GlobalModuleInfo) || {}, + ), + ); + const [shareInfo, setShareInfo] = useState>(() => + buildShareSnapshot((window as any).__FEDERATION__?.__SHARE__), + ); + const [inspectedTab, setInspectedTab] = useState( + window.targetTab, + ); + const [activePanel, setActivePanel] = useState('home'); + const [selectedModuleId, setSelectedModuleId] = useState(null); + const [refreshing, setRefreshing] = useState(false); + + const panelSyncReadyRef = useRef(false); + + const applyModuleUpdate = useCallback((info: GlobalModuleInfo) => { + setModuleInfo(cloneModuleInfo(info)); + const shareSnapshot = buildShareSnapshot( + (window as any).__FEDERATION__?.__SHARE__, + ); + setShareInfo(shareSnapshot); + panelSyncReadyRef.current = true; }, []); - return ( - <> - - - {Object.keys(module).length > 0 || - process.env.NODE_ENV === 'development' ? ( - separateType(moduleInfo), + [moduleInfo], + ); + const moduleKeys = useMemo(() => Object.keys(moduleInfo || {}), [moduleInfo]); + const moduleCount = moduleKeys.length; + const consumerCount = useMemo( + () => Object.keys(consumers || {}).length, + [consumers], + ); + const hasModule = moduleCount > 0 || process.env.NODE_ENV === 'development'; + + useEffect(() => { + if (!moduleKeys.length) { + setSelectedModuleId(null); + return; + } + if (!selectedModuleId || !moduleKeys.includes(selectedModuleId)) { + setSelectedModuleId(moduleKeys[0]); + } + }, [moduleKeys, selectedModuleId]); + useEffect(() => { + const bootstrap = async () => { + const tab = await syncActiveTab(); + setInspectedTab(tab || undefined); + const detach = await getGlobalModuleInfo((info) => + applyModuleUpdate(info), + ); + panelSyncReadyRef.current = true; + return detach; + }; + const cleanupPromise = bootstrap(); + return () => { + cleanupPromise.then((cleanup) => cleanup?.()); + }; + }, [applyModuleUpdate]); + + useEffect(() => { + const updateActiveTab = async (tabId?: number) => { + const tab = await syncActiveTab(tabId); + setInspectedTab(tab || undefined); + if (window.__FEDERATION__?.moduleInfo) { + applyModuleUpdate( + cloneModuleInfo( + window.__FEDERATION__?.moduleInfo as GlobalModuleInfo, + ), + ); + } + await refreshModuleInfo(); + }; + + const onMessage = ( + message: { type?: string; tabId?: number }, + _sender: chrome.runtime.MessageSender, + _sendResponse: (response?: any) => void, + ) => { + if (message?.type === MESSAGE_ACTIVE_TAB_CHANGED) { + updateActiveTab(message.tabId); + } + }; + + chrome.runtime.onMessage.addListener(onMessage); + + return () => { + chrome.runtime.onMessage.removeListener(onMessage); + }; + }, [applyModuleUpdate]); + + const handleRefresh = async () => { + if (refreshing) { + return; + } + setRefreshing(true); + try { + await refreshModuleInfo(); + if (window.__FEDERATION__?.moduleInfo) { + applyModuleUpdate( + cloneModuleInfo( + window.__FEDERATION__?.moduleInfo as GlobalModuleInfo, + ), + ); + } + } finally { + setRefreshing(false); + } + }; + + const resetModuleInfo = useCallback(() => { + const origin = (window.__FEDERATION__?.originModuleInfo || + {}) as GlobalModuleInfo; + applyModuleUpdate(cloneModuleInfo(origin)); + }, [applyModuleUpdate]); + + useEffect(() => { + const shouldAutoSync = + activePanel === 'proxy' || + activePanel === 'dependency' || + activePanel === 'share'; + if (!shouldAutoSync || !panelSyncReadyRef.current) { + return; + } + + let cancelled = false; + + const syncPanelData = async () => { + await refreshModuleInfo(); + if (cancelled) { + return; + } + if (window.__FEDERATION__?.moduleInfo) { + applyModuleUpdate( + cloneModuleInfo( + window.__FEDERATION__?.moduleInfo as GlobalModuleInfo, + ), + ); + } + }; + + void syncPanelData(); + + return () => { + cancelled = true; + }; + }, [activePanel, applyModuleUpdate]); + + const renderContent = () => { + switch (activePanel) { + case 'home': + return ( + setSelectedModuleId(id)} + /> + ); + case 'proxy': + return ( + + ); + case 'dependency': + return hasModule ? ( + + ) : ( +
+ - ) : ( - - )} - - - +
+ ); + case 'share': + return ( + + ); + case 'performance': + return
WIP...
; + default: + return null; + } + }; + + return ( +
+ +
+
+
+
+ Module Federation + DevTools Companion +
+ + + +
+
+
+ Focus Tab + + {inspectedTab?.title || 'Waiting for target'} + +
+
+
+ {moduleCount} + Modules +
+
+ {producer.length} + Remotes +
+
+ {consumerCount} + Consumers +
+
+
+
+
+
{renderContent()}
+
+
+
); }; diff --git a/packages/chrome-devtools/src/component/DependencyGraph/index.module.scss b/packages/chrome-devtools/src/component/DependencyGraph/index.module.scss new file mode 100644 index 00000000000..81493049c2a --- /dev/null +++ b/packages/chrome-devtools/src/component/DependencyGraph/index.module.scss @@ -0,0 +1,106 @@ +.depWrapper { + display: flex; + flex-direction: column; + gap: 16px; + min-height: 340px; + color: #1f2937; +} + +.header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 18px; + padding: 0 6px 6px; + border-bottom: 1px solid rgba(96, 165, 250, 0.3); +} + +.titleBlock { + display: flex; + flex-direction: column; + gap: 6px; +} + +.title { + font-size: 16px; + font-weight: 600; + color: #1f2937; +} + +.subtitle { + font-size: 12px; + color: #4b5563; + max-width: 260px; + line-height: 1.5; +} + +.meta { + display: flex; + align-items: center; + gap: 10px; + background: rgb(229, 231, 235); + padding: 4px 12px; + border-radius: 999px; + border: 1px solid rgba(96, 165, 250, 0.3); +} + +.metaBadge { + font-size: 16px; + font-weight: 600; + color: #1f2937; +} + +.metaLabel { + font-size: 12px; + color: #4b5563; +} + +.canvas { + flex: 1; + padding: 12px; + border-radius: 16px; + border: 1px solid rgba(96, 165, 250, 0.3); + background: linear-gradient( + 160deg, + rgba(243, 244, 246, 0.9) 0%, + rgba(229, 231, 235, 0.7) 42%, + rgba(243, 244, 246, 0.95) 100% + ), + rgba(255, 255, 255, 0.9); + backdrop-filter: blur(4px); + + :global { + .react-flow__handle { + width: 10px; + height: 10px; + border-radius: 50%; + border: 2px solid rgba(96, 165, 250, 0.3); + background: rgba(243, 244, 246, 0.9); + } + + .react-flow__controls-button:hover { + background: rgba(243, 244, 246, 0.9); + } + } +} + +.graph { + width: 100%; + height: 58vh !important; + min-height: 280px; + border-radius: 12px; +} + +.controls { + :global { + .react-flow__controls-button { + background: rgba(243, 244, 246, 0.3); + border-color: rgba(96, 165, 250, 0.3); + color: #1f2937; + } + + .react-flow__controls-button:hover { + background: rgb(255, 255, 255); + } + } +} diff --git a/packages/chrome-devtools/src/component/Graph/index.tsx b/packages/chrome-devtools/src/component/DependencyGraph/index.tsx similarity index 66% rename from packages/chrome-devtools/src/component/Graph/index.tsx rename to packages/chrome-devtools/src/component/DependencyGraph/index.tsx index 28419bfdc75..0c7dd2e69f3 100644 --- a/packages/chrome-devtools/src/component/Graph/index.tsx +++ b/packages/chrome-devtools/src/component/DependencyGraph/index.tsx @@ -13,25 +13,30 @@ import dagre from 'dagre'; import { GlobalModuleInfo } from '@module-federation/sdk'; import { DependencyGraph } from '../../utils/sdk/graph'; -import GraphItem from '../GraphItem'; +import GraphItem from '../DependencyGraphItem'; import { separateType } from '../../utils'; import styles from './index.module.scss'; import 'reactflow/dist/style.css'; -const nodeWidth = 400; -const nodeHeight = 600; +const nodeWidth = 360; +const nodeHeight = 420; const nodeTypes = { graphItem: GraphItem }; const Graph = (props: { snapshot: GlobalModuleInfo }) => { const [nodes, setNodes, onNodesChange] = useNodesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]); const { snapshot } = props; - const { moduleInfo } = window.__FEDERATION__; + const federation = window.__FEDERATION__ || { + moduleInfo: {} as GlobalModuleInfo, + originModuleInfo: {} as GlobalModuleInfo, + }; + const { moduleInfo } = federation; const { consumers } = separateType(moduleInfo); useEffect(() => { const dagreGraph = new dagre.graphlib.Graph(); + // @ts-expect-error dagreGraph.setDefaultEdgeLabel(() => ({})); const getLayoutedElements = ( @@ -52,7 +57,10 @@ const Graph = (props: { snapshot: GlobalModuleInfo }) => { dagre.layout(dagreGraph); nodes.forEach((node) => { - const nodeWithPosition = dagreGraph.node(node.id); + const nodeWithPosition = dagreGraph.node(node.id) as { + x: number; + y: number; + }; node.position = { x: nodeWithPosition.x - nodeWidth / 2, y: nodeWithPosition.y - nodeHeight / 2, @@ -117,18 +125,36 @@ const Graph = (props: { snapshot: GlobalModuleInfo }) => { return (
- - - +
+
+ Dependency Graph + + Visualise how consumers resolve remotes with the current overrides. + +
+
+ {nodes.length} + + {nodes.length === 1 ? 'node rendered' : 'nodes rendered'} + +
+
+ +
+ + + +
); }; diff --git a/packages/chrome-devtools/src/component/DependencyGraphItem/index.module.scss b/packages/chrome-devtools/src/component/DependencyGraphItem/index.module.scss new file mode 100644 index 00000000000..af20e2cec93 --- /dev/null +++ b/packages/chrome-devtools/src/component/DependencyGraphItem/index.module.scss @@ -0,0 +1,119 @@ +.Wrapper { + display: flex; + width: 320px; + border-radius: 18px; + border: 1px solid rgba(96, 165, 250, 0.3); + overflow: hidden; + box-shadow: 0 18px 32px rgba(8, 11, 25, 0.35); + background: linear-gradient( + 140deg, + var(--mf-accent, rgba(243, 244, 246, 0.9)) 0%, + rgba(229, 231, 235, 0.7) 45%, + rgba(255, 255, 255, 0.95) 100% + ), + rgba(255, 255, 255, 0.9); + color: #1f2937; + backdrop-filter: blur(4px); + + :global { + .react-flow__handle { + width: 10px; + height: 10px; + border-radius: 50%; + border: 2px solid rgba(96, 165, 250, 0.3); + background: rgba(243, 244, 246, 0.9); + box-shadow: 0 0 0 4px rgba(96, 165, 250, 0.2); + } + } + + .container { + display: flex; + flex-direction: column; + width: 100%; + padding-bottom: 8px; + } + + .group { + display: flex; + align-items: center; + justify-content: center; + padding: 12px; + background: linear-gradient( + 120deg, + var(--mf-accent, rgba(243, 244, 246, 0.9)) 0%, + rgba(229, 231, 235, 0.7) 100% + ), + rgba(255, 255, 255, 0.9); + } + + .name { + font-size: 15px; + font-weight: 600; + letter-spacing: 0.02em; + color: #1f2937; + } + + .info { + display: flex; + flex-direction: column; + gap: 10px; + margin: 0 12px; + padding: 12px; + border-radius: 14px; + background: rgba(243, 244, 246, 0.4); + border: 1px solid rgba(96, 165, 250, 0.3); + font-size: 11px; + } + + .expose-container { + display: flex; + flex-direction: column; + gap: 6px; + + div { + display: flex; + flex-wrap: wrap; + gap: 6px; + } + } + + .type { + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.04em; + color: #4b5563; + } + + .item { + display: inline-flex; + align-items: center; + padding: 4px 8px; + border-radius: 999px; + background: rgba(243, 244, 246, 0.6); + color: #1f2937; + font-size: 10px; + font-weight: 500; + margin-right: 6px; + max-width: 100%; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + box-shadow: 0 4px 10px rgba(8, 11, 25, 0.45); + } + + .message { + display: flex; + align-items: center; + gap: 6px; + font-size: 11px; + color: #4b5563; + + .item { + margin-right: 0; + padding: 4px 10px; + background: rgba(243, 244, 246, 0.6); + color: #1f2937; + } + } +} diff --git a/packages/chrome-devtools/src/component/GraphItem/index.tsx b/packages/chrome-devtools/src/component/DependencyGraphItem/index.tsx similarity index 83% rename from packages/chrome-devtools/src/component/GraphItem/index.tsx rename to packages/chrome-devtools/src/component/DependencyGraphItem/index.tsx index 897ec8f96db..26ba4a64e9a 100644 --- a/packages/chrome-devtools/src/component/GraphItem/index.tsx +++ b/packages/chrome-devtools/src/component/DependencyGraphItem/index.tsx @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import type { CSSProperties } from 'react'; import { Handle, Position } from 'reactflow'; import styles from './index.module.scss'; @@ -30,15 +31,21 @@ const GraphItem = (props: { fetch(version) .then((response) => response.json()) .then((json) => { + const exposeList = Array.isArray(json?.exposes) ? json.exposes : []; + const sharedList = Array.isArray(json?.shared) ? json.shared : []; exposes = - json.exposes.map((expose: { path: string }) => expose.path) || []; + exposeList.map((expose: { path: string }) => expose.path) || []; shareds = - json.shared.map( + sharedList.map( (share: { name: string; version: string }) => `${share.name}:${share.version}`, ) || []; setExposes(exposes); setShareds(shareds); + }) + .catch(() => { + setExposes([]); + setShareds([]); }); } else { exposes = @@ -53,10 +60,15 @@ const GraphItem = (props: { setExposes(exposes); setShareds(shareds); } - }, []); + }, [isEntryType, remote, version]); + + const accentColor = color || 'rgba(99, 102, 241, 0.45)'; + const style = { + ['--mf-accent' as string]: accentColor, + } as CSSProperties; return ( -
+
diff --git a/packages/chrome-devtools/src/component/Form/index.module.scss b/packages/chrome-devtools/src/component/Form/index.module.scss index 09f1b8106cd..98c06b2000a 100644 --- a/packages/chrome-devtools/src/component/Form/index.module.scss +++ b/packages/chrome-devtools/src/component/Form/index.module.scss @@ -1,58 +1,236 @@ -.container { +.wrapper { display: flex; - justify-content: center; + flex-direction: column; + gap: 18px; + color: #1f2937; +} + +.sectionHeader { + display: flex; + align-items: center; + justify-content: space-between; + gap: 18px; + padding: 12px 16px; + border-radius: 16px; + background: linear-gradient( + 135deg, + rgba(243, 244, 246, 0.9) 0%, + rgba(229, 231, 235, 0.7) 42%, + rgba(243, 244, 246, 0.95) 100% + ), + rgba(255, 255, 255, 0.9); + border: 1px solid rgba(96, 165, 250, 0.3); + box-shadow: 0 10px 24px rgba(8, 11, 25, 0.45); +} - & .checkBox { - transform: scale(1.25); +.heading { + display: flex; + flex-direction: column; + gap: 6px; + flex: 1; +} + +.titleRow { + display: flex; + align-items: center; + gap: 10px; + font-size: 16px; + font-weight: 600; + color: #1f2937; + + :global { + .arco-icon { + color: rgba(243, 244, 246, 0.9); + font-size: 18px; + } } +} - & .input { - margin: 0 1vw 0 0; - flex: 1; - // width: 20px +.title { + letter-spacing: 0.02em; +} + +.subtitle { + font-size: 12px; + color: #4b5563; + line-height: 1.5; +} + +.headerActions { + display: flex; + align-items: center; + gap: 12px; + flex-wrap: wrap; + + & .add { + box-shadow: 0 8px 16px rgba(243, 244, 246, 0.9); } +} + +.badge { + transform: scale(1.4); + margin-right: 6px; +} + +.statusMessage { + font-size: 12px; + color: #4b5563; + max-width: 260px; + line-height: 1.4; +} + +.divider { + width: 1px; + height: 1px; + background: rgba(96, 165, 250, 0.3); +} + +.hmrArea { + display: flex; + align-items: center; + gap: 8px; + font-size: 12px; + color: #4b5563; +} - & .delete { - margin: 0 0 0 1vw; +.switch { + :global { + .arco-switch { + background: rgba(243, 244, 246, 0.9); + border-color: rgba(96, 165, 250, 0.35); + color: #4b5563; + } + + .arco-switch-checked { + background: rgba(243, 244, 246, 0.9); + border-color: rgba(96, 165, 250, 0.35); + } } } -.header { +.rules { + display: flex; + flex-direction: column; + gap: 16px; +} + +.ruleCard { + display: flex; + flex-direction: column; + gap: 14px; + padding: 18px; + border-radius: 18px; + border: 1px solid rgba(96, 165, 250, 0.3); + background: rgba(255, 255, 255, 0.9); + box-shadow: 0 15px 32px rgba(8, 11, 25, 0.45); +} + +.ruleHeader { display: flex; align-items: center; - margin: 1vh 0; + justify-content: space-between; +} - & .add { - margin: 0 0.5vw; +.toggle { + :global { + .arco-checkbox { + transform: scale(1.4); + } + + .arco-checkbox-icon { + border-radius: 6px; + border-color: rgba(96, 165, 250, 0.35); + background: rgba(243, 244, 246, 0.9); + } + + .arco-checkbox-checked .arco-checkbox-icon { + background: rgba(243, 244, 246, 0.9); + border-color: rgba(96, 165, 250, 0.35); + } } +} - & .title { - margin: 0 0.5vw; +.inputs { + display: flex; + flex-direction: column; + gap: 12px; +} + +@media (min-width: 520px) { + .inputs { + flex-direction: row; } +} + +.field { + flex: 1; - & .status { - display: flex; - flex: 1; - justify-content: flex-end; - align-items: center; + :global { + .arco-form-item-content { + width: 100%; + } + + .arco-select-view { + background: rgba(243, 244, 246, 0.9); + border: 1px solid rgba(96, 165, 250, 0.3); + border-radius: 14px; + color: #1f2937; + min-height: 42px; + padding: 6px 12px; + } - & .message { - flex: 1; + .arco-select-view-input { + color: #4b5563; } - & .switch { - margin-left: 0.5vw; + .arco-select-view-placeholder { + color: #4b5563; } } +} + +.dropdown { + background: rgba(255, 255, 255, 0.9); + border: 1px solid rgba(96, 165, 250, 0.3); + box-shadow: 0 16px 30px rgba(8, 11, 25, 0.45); - & .headerSlot { - display: flex; - align-items: center; + :global { + .arco-select-option { + color: #4b5563; + } + + .arco-select-option:hover, + .arco-select-option.arco-select-option-selected { + background: rgba(243, 244, 246, 0.9); + } } +} - & .badge { - display: flex; - transform: scale(1.6); - margin: 0 0.6vw; +.delete { + box-shadow: 0 8px 16px rgba(248, 113, 113, 0.18); +} + +.emptyWrapper { + border-radius: 16px; + border: 1px dashed rgba(96, 165, 250, 0.3); + padding: 28px 16px; + background: rgba(255, 255, 255, 0.9); + display: flex; + justify-content: center; +} + +.empty { + :global { + .arco-empty-description { + color: #4b5563; + } } } + +.footerHint { + font-size: 11px; + color: #4b5563; + text-align: right; + letter-spacing: 0.04em; + text-transform: uppercase; +} diff --git a/packages/chrome-devtools/src/component/Form/index.tsx b/packages/chrome-devtools/src/component/Form/index.tsx index adaa2b37f25..a3ac2988027 100644 --- a/packages/chrome-devtools/src/component/Form/index.tsx +++ b/packages/chrome-devtools/src/component/Form/index.tsx @@ -61,7 +61,11 @@ const FormComponent = (props: FormProps & RootComponentProps) => { getVersion, customValueValidate, } = props; - const { moduleInfo } = window.__FEDERATION__; + const federation = window.__FEDERATION__ || { + moduleInfo: {} as any, + originModuleInfo: {} as any, + }; + const { moduleInfo } = federation; let { producer } = separateType(moduleInfo); const filterDupMap = new Map(); producer = producer.filter((t) => { @@ -103,7 +107,7 @@ const FormComponent = (props: FormProps & RootComponentProps) => { const validateKey = ( key: string, - callback: { (error?: ReactNode): void; (arg0: string | undefined): any }, + callback: (error?: string) => void, index: number, ) => { const status = getCheckStatus(index); @@ -121,17 +125,24 @@ const FormComponent = (props: FormProps & RootComponentProps) => { if (key) { statusSet[index].keyStatus = true; - flushSync(() => setFormStatus(statusSet)); - return callback(); + // 在 React 19 中,使用 setTimeout 来确保状态更新在下一个事件循环中执行 + setTimeout(() => { + setFormStatus(statusSet); + callback(); + }, 0); + return; } + statusSet[index].keyStatus = false; - flushSync(() => setFormStatus(statusSet)); + setTimeout(() => { + setFormStatus(statusSet); + }, 0); return callback('Module name can not be empty'); }; const validateValue = ( value: string, - callback: { (error?: ReactNode): void; (arg0: string | undefined): any }, + callback: (error?: string) => void, index: number, ) => { const status = getCheckStatus(index); @@ -154,12 +165,18 @@ const FormComponent = (props: FormProps & RootComponentProps) => { customValueValidate?.(value) ) { statusSet[index].valueStatus = true; - flushSync(() => setFormStatus(statusSet)); - return callback(); + // 在 React 19 中,使用 setTimeout 来确保状态更新在下一个事件循环中执行 + setTimeout(() => { + setFormStatus(statusSet); + callback(); + }, 0); + return; } statusSet[index].valueStatus = false; - flushSync(() => setFormStatus(statusSet)); + setTimeout(() => { + setFormStatus(statusSet); + }, 0); return callback( 'The module information format is incorrect, check the format in the upper left corner', ); @@ -198,32 +215,33 @@ const FormComponent = (props: FormProps & RootComponentProps) => { return ( {(fields, { add, remove }) => ( -
-
- - Example: Customize the remote module address, which should end - with 「.json」, for example key: @module-federation/button, - value: http://localhost:3000/mf-manifest.json -
- } - > - - -
Module Proxy
-
{fields.length ? ( - <> +
{fields.map((item, index) => ( -
-
+
+
- + +
- -
+
- validateKey(value, cb, index), + validator: (value, cb) => { + const isValid = !!value; + if (isValid) { + cb(); + validateKey(value, () => {}, index); + } else { + cb('Module name can not be empty'); + validateKey(value, () => {}, index); + } + }, }, ]} + className={styles.field} > -
- -
- validateValue(value, cb, index), + validator: (value, cb) => { + const isValid = + validateCustom(value) || + validateSemver(value) || + validatePort(value) || + customValueValidate?.(value); + if (isValid) { + cb(); + validateValue(value, () => {}, index); + } else { + cb( + 'The module information format is incorrect, check the format in the upper left corner', + ); + validateValue(value, () => {}, index); + } + }, }, ]} + className={styles.field} >
- -
))} - +
) : ( - +
+ +
)} + +
+ Changes persist per domain and refresh the inspected tab when valid. +
)} diff --git a/packages/chrome-devtools/src/component/Graph/index.module.scss b/packages/chrome-devtools/src/component/Graph/index.module.scss deleted file mode 100644 index 496cdf5ece0..00000000000 --- a/packages/chrome-devtools/src/component/Graph/index.module.scss +++ /dev/null @@ -1,14 +0,0 @@ -.depWrapper { - border: 1px solid #e5e6ec; - margin-top: 16px; - padding-top: 14px; - border-radius: 8px; - - .table { - margin: 8px 0 20px; - } - - .graph { - height: 80vh !important; - } -} diff --git a/packages/chrome-devtools/src/component/GraphItem/index.module.scss b/packages/chrome-devtools/src/component/GraphItem/index.module.scss deleted file mode 100644 index 28198925e50..00000000000 --- a/packages/chrome-devtools/src/component/GraphItem/index.module.scss +++ /dev/null @@ -1,66 +0,0 @@ -.Wrapper { - display: flex; - box-sizing: border-box; - border-radius: 10px; - margin: 0; - padding: 0; - width: 300px; - overflow: hidden; - - .container { - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - margin: 0; - padding: 0; - - .group { - display: flex; - align-items: center; - margin-bottom: 3px; - width: 100%; - padding: 5px 0; - - .name { - color: white; - text-align: center; - margin: 0 auto; - } - } - - .info { - display: flex; - flex-direction: column; - background-color: white; - margin: 0 4px 4px 4px; - padding: 10px; - border-radius: 0 0 5px 5px; - font-size: 12px; - .expose-container { - display: flex; - margin-bottom: 5px; - } - .type { - font-weight: bold; - margin-right: 10px; - } - .item { - display: inline-block; - padding: 5px; - background: lightgray; - border-radius: 15px; - font-size: 8px; - margin-right: 5px; - margin-bottom: 5px; - font-weight: 300; - text-overflow: ellipsis; - overflow: hidden; - } - } - - .message { - display: flex; - } - } -} diff --git a/packages/chrome-devtools/src/component/Home/index.module.scss b/packages/chrome-devtools/src/component/Home/index.module.scss new file mode 100644 index 00000000000..1b86e3aac6f --- /dev/null +++ b/packages/chrome-devtools/src/component/Home/index.module.scss @@ -0,0 +1,188 @@ +.home { + display: flex; + flex-direction: column; + gap: 20px; + height: 100%; +} + +.moduleSelector { + display: flex; + gap: clamp(12px, 2vw, 20px); + flex: 1; + min-height: 0; +} + +.moduleList { + width: clamp(220px, 28%, 320px); + max-width: 40%; + padding: 12px; + border-radius: 16px; + border: 1px solid rgba(96, 165, 250, 0.3); + background: rgba(255, 255, 255, 0.9); + display: flex; + flex-direction: column; + gap: 8px; + overflow-y: auto; +} + +.moduleItem { + border: 1px solid transparent; + border-radius: 12px; + padding: 10px 12px; + background: rgba(243, 244, 246, 0.4); + color: #1f2937; + font-size: 13px; + text-align: left; + cursor: pointer; + transition: all 0.15s ease; +} + +.moduleItem:hover { + border-color: rgba(34, 197, 94, 0.5); + background: rgba(243, 244, 246, 0.6); +} + +.moduleItemActive { + border-color: rgba(34, 197, 94, 0.6); + background: rgba(243, 244, 246, 0.8); + box-shadow: 0 10px 22px rgba(34, 197, 94, 0.2); +} + +.moduleName { + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.moduleDetail { + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; + padding: 16px 20px; + border-radius: 20px; + border: 1px solid rgba(96, 165, 250, 0.3); + background: rgba(255, 255, 255, 0.9); +} + +.detailHeader { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 16px; +} + +.detailTitle { + font-size: 16px; + font-weight: 600; + color: #1f2937; + word-break: break-word; +} + +.detailBody { + flex: 1; + overflow-y: auto; + display: flex; + flex-direction: column; + gap: 12px; +} + +.detailRow { + display: flex; + flex-direction: column; + gap: 6px; + padding: 12px; + border-radius: 14px; + background: rgba(243, 244, 246, 0.4); + border: 1px solid rgba(96, 165, 250, 0.3); +} + +.detailLabel { + font-size: 12px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: #4b5563; +} + +.detailValue { + font-size: 13px; + color: #1f2937; +} + +.valueText { + word-break: break-word; +} + +.pillGroup { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.pill { + padding: 4px 8px; + border-radius: 999px; + background: rgba(243, 244, 246, 0.4); + border: 1px solid rgba(96, 165, 250, 0.3); + font-size: 11px; + color: #1f2937; + max-width: 100%; + text-overflow: ellipsis; + overflow: hidden; +} + +.jsonBlock { + margin: 0; + padding: 12px; + border-radius: 12px; + background: rgba(243, 244, 246, 0.4); + border: 1px solid rgba(96, 165, 250, 0.3); + font-size: 12px; + color: #1f2937; + overflow-x: auto; +} + +.emptyState { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + border-radius: 18px; + border: 1px dashed rgba(96, 165, 250, 0.3); + background: rgba(255, 255, 255, 0.9); +} + +@media (max-width: 960px) { + .moduleSelector { + flex-direction: column; + } + + .moduleList { + width: 100%; + max-width: none; + flex-direction: row; + flex-wrap: nowrap; + overflow-x: auto; + padding: 10px; + } + + .moduleItem { + min-width: 180px; + } + + .moduleDetail { + width: 100%; + padding: 14px 18px; + } +} + +@media (max-width: 640px) { + .moduleItem { + min-width: 150px; + } + + .detailRow { + padding: 10px; + } +} diff --git a/packages/chrome-devtools/src/component/Home/index.tsx b/packages/chrome-devtools/src/component/Home/index.tsx new file mode 100644 index 00000000000..3cdfef65eeb --- /dev/null +++ b/packages/chrome-devtools/src/component/Home/index.tsx @@ -0,0 +1,181 @@ +import { useMemo } from 'react'; +import { Empty, Select, Tag } from '@arco-design/web-react'; +import type { GlobalModuleInfo } from '@module-federation/sdk'; + +import styles from './index.module.scss'; + +interface HomeProps { + moduleInfo: GlobalModuleInfo; + selectedModuleId: string | null; + onSelectModule: (moduleId: string) => void; +} + +const renderValue = (value: any) => { + if (value === undefined || value === null) { + return null; + } + if (Array.isArray(value)) { + if (!value.length) { + return null; + } + return ( +
+ {value.map((item, index) => ( + + {typeof item === 'string' ? item : JSON.stringify(item)} + + ))} +
+ ); + } + if (typeof value === 'object') { + return ( +
{JSON.stringify(value, null, 2)}
+ ); + } + return {String(value)}; +}; + +const extractDetailSections = (moduleSnapshot: any) => { + if (!moduleSnapshot) { + return []; + } + + const sections: Array<{ label: string; value: any }> = []; + const remoteEntry = + moduleSnapshot.remoteEntry || + moduleSnapshot.entry || + moduleSnapshot.version; + if (remoteEntry) { + sections.push({ + label: 'Remote Entry', + value: remoteEntry, + }); + } + + if (moduleSnapshot.version) { + sections.push({ + label: 'Version', + value: moduleSnapshot.version, + }); + } + + if (moduleSnapshot.consumerList) { + sections.push({ + label: 'Consumers', + value: moduleSnapshot.consumerList, + }); + } + + if (moduleSnapshot.modules) { + sections.push({ + label: 'Exposes', + value: moduleSnapshot.modules, + }); + } + + if (moduleSnapshot.remotesInfo) { + sections.push({ + label: 'Remotes', + value: moduleSnapshot.remotesInfo, + }); + } + + if (moduleSnapshot.shared) { + sections.push({ + label: 'Shared', + value: moduleSnapshot.shared, + }); + } + + if (!sections.length) { + sections.push({ + label: 'Snapshot', + value: moduleSnapshot, + }); + } + + return sections; +}; + +const Home = (props: HomeProps) => { + const { moduleInfo, selectedModuleId, onSelectModule } = props; + const moduleEntries = useMemo( + () => + Object.entries(moduleInfo || {}).filter(([key]) => key !== 'extendInfos'), + [moduleInfo], + ); + + const [currentModuleId, currentSnapshot] = useMemo(() => { + if (!moduleEntries.length) { + return [null, null] as [string | null, any]; + } + const entry = + moduleEntries.find(([moduleId]) => moduleId === selectedModuleId) || + moduleEntries[0]; + return entry; + }, [moduleEntries, selectedModuleId]); + + const detailSections = useMemo( + () => extractDetailSections(currentSnapshot), + [currentSnapshot], + ); + + if (!moduleEntries.length || !currentModuleId) { + return ( +
+ +
+ ); + } + return ( +
+ +
+
+
+ {currentModuleId} +
+
+ {detailSections.map((section) => { + const content = renderValue(section.value); + if (!content) { + return null; + } + return ( +
+
{section.label}
+
{content}
+
+ ); + })} +
+
+
+
+ ); +}; + +export default Home; diff --git a/packages/chrome-devtools/src/component/Layout/index.module.scss b/packages/chrome-devtools/src/component/Layout/index.module.scss index b071eb3e9aa..fb7488f2626 100644 --- a/packages/chrome-devtools/src/component/Layout/index.module.scss +++ b/packages/chrome-devtools/src/component/Layout/index.module.scss @@ -1,55 +1,79 @@ -.select { - margin-top: 1vh; +.wrapper { + display: flex; + flex-direction: column; + gap: 24px; + flex: 1; } -.card { +.summaryCard { + padding: 18px 20px; + border-radius: 18px; + border: 1px solid rgba(96, 165, 250, 0.3); + background: linear-gradient( + 120deg, + rgba(243, 244, 246, 0.9) 0%, + rgba(229, 231, 235, 0.7) 40%, + rgba(243, 244, 246, 0.95) 100% + ), + rgba(255, 255, 255, 0.9); + box-shadow: 0 12px 28px rgba(8, 11, 25, 0.45); display: flex; - height: 4vh; - align-items: center; - - & .appName { - margin: 1vh 0; - } + flex-direction: column; + gap: 16px; + min-height: 110px; } -.tagContainer { +.summaryHeader { display: flex; - align-items: center; - margin-bottom: 1vh; - color: rgb(78, 89, 105); + flex-direction: column; + gap: 6px; +} + +.summaryTitle { + font-size: 16px; + font-weight: 600; + color: #1f2937; +} - & .tag { - margin-left: 1vw; - } +.summaryHint { + font-size: 12px; + color: #4b5563; } -.header { +.chipGroup { display: flex; align-items: center; - margin: 1vh 0; - - & .add { - margin: 0 0.5vw; - } - - & .title { - margin: 0 0.5vw; - } - - & .status { - display: flex; - flex: 1; - justify-content: flex-end; - align-items: center; - - & .switch { - margin-left: 0.5vw; - } - } - - & .badge { - display: flex; - transform: scale(1.6); - margin: 0 0.6vw; - } + flex-wrap: wrap; + gap: 8px; +} + +.chip, +.moreChip, +.chipPlaceholder { + padding: 6px 10px; + border-radius: 12px; + border: 1px solid rgba(96, 165, 250, 0.3); + background: rgba(255, 255, 255, 0.9); + font-size: 12px; + color: #1f2937; + letter-spacing: 0.02em; +} + +.chipPlaceholder { + border-style: dashed; + color: #4b5563; + background: rgba(255, 255, 255, 0.9); +} + +.moreChip { + background: rgba(243, 244, 246, 0.4); + border-color: rgba(96, 165, 250, 0.3); +} + +.formSection { + border-radius: 20px; + padding: 22px 24px; + border: 1px solid rgba(96, 165, 250, 0.3); + background: rgba(255, 255, 255, 0.9); + box-shadow: 0 15px 32px rgba(8, 11, 25, 0.35); } diff --git a/packages/chrome-devtools/src/component/Layout/index.tsx b/packages/chrome-devtools/src/component/Layout/index.tsx index a416f7ee135..be07faa080e 100644 --- a/packages/chrome-devtools/src/component/Layout/index.tsx +++ b/packages/chrome-devtools/src/component/Layout/index.tsx @@ -1,5 +1,5 @@ -import { useEffect, useState } from 'react'; -import { useDebounceFn, useUpdateEffect } from 'ahooks'; +import { useEffect, useMemo, useState, useRef } from 'react'; +import { useDebounceFn, useUpdateEffect, useUnmount } from 'ahooks'; import { Form, FormInstance } from '@arco-design/web-react'; import { GlobalModuleInfo, @@ -8,7 +8,7 @@ import { import type { Federation } from '@module-federation/runtime'; import FormComponent from '../Form'; -import Dependency from '../Graph'; +import styles from './index.module.scss'; import { getModuleInfo, getScope, @@ -17,6 +17,7 @@ import { separateType, reloadPage, setChromeStorage, + getStorageValue, mergeStorage, removeStorageKey, removeStorage, @@ -39,6 +40,24 @@ interface FormItemType { value: string; checked: boolean; } + +const sortRulesForSignature = (rules: Array) => + [...rules] + .sort((a, b) => { + const keyCompare = (a.key || '').localeCompare(b.key || ''); + if (keyCompare !== 0) { + return keyCompare; + } + return (a.value || '').localeCompare(b.value || ''); + }) + .map((rule) => ({ + key: rule.key || '', + value: rule.value || '', + checked: Boolean(rule.checked), + })); + +const getEffectiveSignature = (rules: Array) => + rules.length ? JSON.stringify(sortRulesForSignature(rules)) : ''; declare global { interface Window { __FEDERATION__: Federation & { @@ -60,63 +79,150 @@ const Layout = ( handleProxyAddress, customValueValidate, headerSlot, + onModuleInfoChange, + onModuleInfoReset, } = props; const { producer } = separateType(moduleInfo); + const producerKey = useMemo(() => producer.join('|'), [producer]); const [condition, setCondition] = useState(statusInfo.processing); const [formStatus, setFormStatus] = useState>([]); - const [snapshot, setSnapshot] = useState(moduleInfo); const [form] = Form.useForm(); const [enableHMR, setEnalbeHMR] = useState('disable'); + const lastFormSignatureRef = useRef(''); + const lastEffectiveRulesRef = useRef(''); + const lastRawRulesRef = useRef>([]); + + const ensureFederationContext = () => { + if (!window.__FEDERATION__) { + window.__FEDERATION__ = { + originModuleInfo: moduleInfo || ({} as GlobalModuleInfo), + moduleInfo: moduleInfo || ({} as GlobalModuleInfo), + } as Federation & { + originModuleInfo: GlobalModuleInfo; + moduleInfo: GlobalModuleInfo; + }; + } + if (!window.__FEDERATION__.originModuleInfo) { + window.__FEDERATION__.originModuleInfo = + moduleInfo || ({} as GlobalModuleInfo); + } + if (!window.__FEDERATION__.moduleInfo) { + window.__FEDERATION__.moduleInfo = moduleInfo || ({} as GlobalModuleInfo); + } + }; + + useEffect(() => { + ensureFederationContext(); + window.__FEDERATION__.moduleInfo = JSON.parse( + JSON.stringify(moduleInfo || {}), + ) as GlobalModuleInfo; + window.__FEDERATION__.originModuleInfo = JSON.parse( + JSON.stringify(moduleInfo || {}), + ) as GlobalModuleInfo; + const rawRules = form.getFieldValue(proxyFormField) || []; + lastRawRulesRef.current = JSON.parse(JSON.stringify(rawRules)); + }, [moduleInfo, form]); + + const collectEffectiveRules = ( + rules: Array, + statusList: Array, + ) => { + return rules.reduce((memo: Array, current, idx) => { + if (!current?.checked) { + return memo; + } + const status = statusList[idx]; + const keyValid = status ? status.keyStatus : Boolean(current.key); + const valueValid = status ? status.valueStatus : Boolean(current.value); + if (!keyValid || !valueValid) { + return memo; + } + const duplicate = JSON.parse(JSON.stringify(current)); + if (handleProxyAddress) { + duplicate.value = handleProxyAddress(duplicate.value); + } + memo.push(duplicate); + return memo; + }, []); + }; + + const hasPendingRule = ( + rules: Array, + statusList: Array, + ) => { + return rules.some((rule, idx) => { + if (!rule?.checked) { + return false; + } + const status = statusList[idx]; + if (!status) { + return Boolean(rule.key) && !rule.value; + } + return Boolean(status.keyStatus) && !status.valueStatus; + }); + }; const { run } = useDebounceFn( async (formData) => { + ensureFederationContext(); window.__FEDERATION__.moduleInfo = JSON.parse( JSON.stringify(window.__FEDERATION__.originModuleInfo), ); - const filterFormData = formData[proxyFormField].reduce( - (memo: Array, current: FormItemType, idx: number) => { - if (!formStatus[idx]) { - return memo; - } - - const { keyStatus, valueStatus } = formStatus[idx]; - if (!keyStatus || !valueStatus || !current.checked) { - return memo; - } - const duplicate = JSON.parse(JSON.stringify(current)); - if (handleProxyAddress) { - const value = handleProxyAddress(duplicate.value); - duplicate.value = value; - } - return [...memo, duplicate]; - }, - [], - ); + const rawRules = formData[proxyFormField] || []; + const rawSignature = JSON.stringify(rawRules); + if (rawSignature === lastFormSignatureRef.current) { + return; + } + const effectiveRules = collectEffectiveRules(rawRules, formStatus); + const effectiveSignature = getEffectiveSignature(effectiveRules); + const pendingRule = hasPendingRule(rawRules, formStatus); + const hadPreviousEffective = + lastEffectiveRulesRef.current !== '' && + lastEffectiveRulesRef.current !== '[]'; try { setCondition(statusInfo.processing); - if (!filterFormData.length) { - await removeStorage(MODULE_DEVTOOL_IDENTIFIER); - await removeStorage(BROWSER_ENV_KEY); - - await removeStorageKey(__FEDERATION_DEVTOOLS__, 'overrides'); - await injectScript(reloadPage, false); - setCondition(statusInfo.noProxy); - setSnapshot(window.__FEDERATION__.originModuleInfo); + if (!effectiveRules.length) { + if (pendingRule) { + return; + } + if (hadPreviousEffective) { + await removeStorage(MODULE_DEVTOOL_IDENTIFIER); + await removeStorage(BROWSER_ENV_KEY); + await removeStorageKey(__FEDERATION_DEVTOOLS__, 'overrides'); + await injectScript(reloadPage, false); + setCondition(statusInfo.noProxy); + lastEffectiveRulesRef.current = ''; + if (typeof onModuleInfoReset === 'function') { + onModuleInfoReset(); + } else { + onModuleInfoChange?.(window.__FEDERATION__.originModuleInfo); + } + } else { + setCondition(statusInfo.noProxy); + } + return; + } + if (effectiveSignature === lastEffectiveRulesRef.current) { + return; + } + if (rawRules.every((rule: FormItemType) => !rule.value)) { return; } const { moduleInfo, status, overrides } = handleSnapshot - ? await handleSnapshot(filterFormData) - : await getModuleInfo(filterFormData); + ? await handleSnapshot(effectiveRules) + : await getModuleInfo(effectiveRules); const snapshotJson = JSON.stringify(moduleInfo); await setStorage(MODULE_DEVTOOL_IDENTIFIER, snapshotJson); await setStorage(BROWSER_ENV_KEY); await mergeStorage(__FEDERATION_DEVTOOLS__, 'overrides', overrides); + await injectScript(reloadPage, false); window.__FEDERATION__.moduleInfo = moduleInfo; - setSnapshot(moduleInfo); + onModuleInfoChange?.(moduleInfo); setCondition(statusInfo[status]); + lastEffectiveRulesRef.current = effectiveSignature; } catch (e) { console.log(e); setCondition(statusInfo.error); @@ -128,30 +234,94 @@ const Layout = ( ); useEffect(() => { - setSnapshot(moduleInfo); - }, [moduleInfo]); + ensureFederationContext(); + let cancelled = false; - useEffect(() => { - getScope().then(async (scope) => { + const hydrateForm = async () => { + const scope = await getScope(); const data = await chrome.storage.sync.get([FormID]); const config = data?.[FormID]?.[scope]; let storeData; if (isObject(config)) { storeData = JSON.parse(JSON.stringify(config)); - storeData[proxyFormField] = storeData[proxyFormField]?.filter( - (item: { key: string }) => producer.includes(item.key), - ); - if (!storeData[proxyFormField]?.length) { - storeData = defaultModuleData; + if (producer.length) { + storeData[proxyFormField] = storeData[proxyFormField]?.filter( + (item: { key: string }) => producer.includes(item.key), + ); + if (!storeData[proxyFormField]?.length) { + storeData = JSON.parse(JSON.stringify(defaultModuleData)); + } } } else { - storeData = defaultModuleData; + storeData = JSON.parse(JSON.stringify(defaultModuleData)); } - form.setFieldsValue(storeData); - }); - }, []); + let overridesApplied = false; + try { + const overridesState = await getStorageValue(__FEDERATION_DEVTOOLS__); + if (typeof overridesState === 'string' && overridesState) { + const parsedState = JSON.parse(overridesState); + const overrides = parsedState?.overrides; + if (isObject(overrides)) { + const overrideRules = Object.entries(overrides) + .map(([key, value]) => ({ + key, + value: typeof value === 'string' ? value : '', + checked: true, + })) + .filter( + (rule): rule is FormItemType => + Boolean(rule.key) && Boolean(rule.value), + ); + const filteredRules = producer.length + ? overrideRules.filter((rule) => producer.includes(rule.key)) + : overrideRules; + if (filteredRules.length) { + storeData = { + ...storeData, + [proxyFormField]: filteredRules, + }; + overridesApplied = true; + } + } + } + } catch (error) { + console.warn( + '[MF Devtools] hydrate overrides from localStorage failed', + error, + ); + } + + if (!cancelled) { + form.setFieldsValue(storeData); + lastFormSignatureRef.current = JSON.stringify(storeData); + const rules: Array = Array.isArray( + storeData[proxyFormField], + ) + ? storeData[proxyFormField] + : []; + const effectiveRules = collectEffectiveRules(rules, []); + lastEffectiveRulesRef.current = getEffectiveSignature(effectiveRules); + lastRawRulesRef.current = JSON.parse(JSON.stringify(rules)); + setFormStatus( + rules.map((rule) => ({ + keyStatus: Boolean(rule?.key), + valueStatus: Boolean(rule?.value), + })), + ); + if (overridesApplied) { + setChromeStorage(storeData); + } + } + }; + + hydrateForm(); + + return () => { + cancelled = true; + }; + }, [moduleInfo, producerKey, form]); useEffect(() => { chrome.storage.sync.get([ENABLEHMR]).then((data) => { @@ -167,9 +337,25 @@ const Layout = ( }, []); useUpdateEffect(() => { + if (!producer.length) { + return; + } const formData = form.getFieldsValue(); + const signature = JSON.stringify(formData); + if (signature === lastFormSignatureRef.current) { + return; + } + lastFormSignatureRef.current = signature; + const effectiveRules = collectEffectiveRules( + formData[proxyFormField] || [], + formStatus, + ); + const effectiveSignature = getEffectiveSignature(effectiveRules); + if (effectiveSignature === lastEffectiveRulesRef.current) { + return; + } run(formData); - }, []); + }, [producerKey, formStatus]); const validateForm = ( form: FormInstance, @@ -184,6 +370,11 @@ const Layout = ( const onValuesChange = (target: any, formData: any) => { validateForm(form); + const signature = JSON.stringify(formData); + if (signature === lastFormSignatureRef.current) { + return; + } + lastFormSignatureRef.current = signature; setChromeStorage(formData); run(formData); }; @@ -201,31 +392,68 @@ const Layout = ( injectScript(reloadPage, false); }; + const remotePreview = producer + .map((id) => { + const [, name] = id.split(':'); + return name || id; + }) + .filter(Boolean); + const previewList = remotePreview.slice(0, 4); + const extraCount = + remotePreview.length > previewList.length + ? remotePreview.length - previewList.length + : 0; + return ( - <> -
onValuesChange(value, formData)} - initialValues={defaultModuleData} - > - +
+
+ Remotes in scope + + Override manifests to verify integration without redeploying. + +
+
+ {previewList.length ? ( + previewList.map((name) => ( + + {name} + + )) + ) : ( + + Waiting for module map + + )} + {extraCount > 0 && ( + +{extraCount} more + )} +
+
+ +
+ validateForm(form)} - enableHMR={enableHMR} - onHMRChange={onHMRChange} - versionList={versionList} - setVersionList={setVersionList} - getVersion={getVersion} - customValueValidate={customValueValidate} - headerSlot={headerSlot} - /> - - - - + onValuesChange={(value, formData) => onValuesChange(value, formData)} + initialValues={defaultModuleData} + > + validateForm(form)} + enableHMR={enableHMR} + onHMRChange={onHMRChange} + versionList={versionList} + setVersionList={setVersionList} + getVersion={getVersion} + customValueValidate={customValueValidate} + headerSlot={headerSlot} + /> + +
+
); }; diff --git a/packages/chrome-devtools/src/component/ShareGraph/adapter.ts b/packages/chrome-devtools/src/component/ShareGraph/adapter.ts new file mode 100755 index 00000000000..bf68e283065 --- /dev/null +++ b/packages/chrome-devtools/src/component/ShareGraph/adapter.ts @@ -0,0 +1,251 @@ +import { parseEntry } from '@module-federation/sdk'; +import type { + Normalized, + NormalizedVersionInfo, + ShareScopeMap, + GlobalShareScopeMap, + Shared, +} from './global'; + +function isPlainObject(v: object): v is Record { + return Object.prototype.toString.call(v) === '[object Object]'; +} + +function toName(x: unknown): string { + if (x == null) { + return 'unknown'; + } + if (typeof x === 'string') { + return x; + } + if (isPlainObject(x) && typeof x.name === 'string') { + return x.name; + } + try { + return JSON.stringify(x); + } catch { + return String(x); + } +} + +// 往 normalized 聚合一个 Shared +function add( + normalized: Normalized, + scope: string, + share: string, + version: string, + shared: Shared, + loaded: boolean, + instance?: string, +) { + if (!normalized[scope]) { + normalized[scope] = {}; + } + if (!normalized[scope][share]) { + normalized[scope][share] = { versions: {} }; + } + const vmap = normalized[scope][share].versions; + if (!vmap[version]) { + vmap[version] = [] as NormalizedVersionInfo[]; + } + + const versionInfo: NormalizedVersionInfo = { + instance: instance || 'unknown', + providers: [], + consumers: [], + loaded, + }; + + const providerName = shared?.from ? toName(shared.from) : null; + if (providerName) { + versionInfo.providers.push(providerName); + } + const consumers = Array.isArray(shared?.useIn) + ? shared.useIn.map(toName) + : []; + for (const c of consumers) { + if (c) { + versionInfo.consumers.push(c); + } + } + + // 添加到版本数组 + vmap[version].push(versionInfo); +} + +function normalizeInstance( + input: ShareScopeMap, + normalized: Normalized, + instance?: string, +) { + for (const [scope, scopeObj] of Object.entries(input || {})) { + if (!isPlainObject(scopeObj)) { + continue; + } + for (const [share, shareObj] of Object.entries(scopeObj || {})) { + if (isPlainObject(shareObj)) { + // shareObj 可能是 {version: Shared} 或直接 Shared(缺失版本层) + const entries = Object.entries(shareObj); + if ( + entries.length && + isPlainObject(entries[0][1]) && + ('from' in entries[0][1] || 'useIn' in entries[0][1]) + ) { + // eslint-disable-next-line max-depth + for (const [version, shared] of entries) { + add( + normalized, + scope, + share, + version, + shared, + Boolean(shared.loaded), + instance, + ); + } + } else if ('from' in shareObj || 'useIn' in shareObj) { + // 缺失版本层,兜底 unknown + add( + normalized, + scope, + share, + 'unknown', + shareObj as Shared, + Boolean(shareObj.loaded), + instance, + ); + } else { + // 不可识别,尝试兜底 + add( + normalized, + scope, + share, + 'unknown', + shareObj as Shared, + Boolean(shareObj.loaded), + instance, + ); + } + } + } + } +} + +export function normalizeGlobalShare( + input: Record, +): Normalized { + const normalized: Normalized = {}; + if (!isPlainObject(input)) { + throw new Error('输入必须是对象格式'); + } + + // 验证是否为GlobalShareScopeMap格式 + if (!validateGlobalShareScopeMapFormat(input)) { + throw new Error('数据格式不符合GlobalShareScopeMap规范,请检查数据结构'); + } + + try { + for (const [instance, scopeMap] of Object.entries( + input as GlobalShareScopeMap, + )) { + if (!isPlainObject(scopeMap)) { + continue; + } + // compat legacy data + if (instance === 'default') { + continue; + } + normalizeInstance(scopeMap, normalized, parseEntry(instance).name); + } + } catch (e) { + console.warn('normalizeGlobalShare 异常', e); + throw new Error( + `数据处理失败: ${e instanceof Error ? e.message : String(e)}`, + ); + } + return normalized; +} + +function validateGlobalShareScopeMapFormat( + input: Record, +): boolean { + if (!isPlainObject(input)) { + return false; + } + + // 检查是否至少有一个实例 + const instances = Object.keys(input); + if (instances.length === 0) { + return false; + } + + // 检查每个实例是否包含scope结构 + for (const instance of instances) { + const scopeMap = input[instance]; + if (!isPlainObject(scopeMap as Record)) { + continue; + } + + const scopes = Object.keys(scopeMap as Record); + if (scopes.length === 0) { + continue; + } + + // 检查至少一个scope包含share结构 + for (const scope of scopes) { + const shareMap = (scopeMap as Record)[scope]; + if (!isPlainObject(shareMap as Record)) { + continue; + } + + const shares = Object.keys(shareMap as Record); + if (shares.length > 0) { + return true; // 找到有效的scope/share结构 + } + } + } + + return false; +} + +export function validateNormalized(n: Normalized): boolean { + try { + const scopes = Object.keys(n || {}); + if (!scopes.length) { + return false; + } + for (const s of scopes) { + const shares = n[s] || {}; + const shareKeys = Object.keys(shares); + if (!shareKeys.length) { + continue; + } + for (const sh of shareKeys) { + const vmap = shares[sh]?.versions || {}; + if (Object.keys(vmap).length) { + return true; // 找到有效的scope/share/version结构 + } + } + } + return false; + } catch { + return false; + } +} + +export function safeStringify(obj: NormalizedVersionInfo[], space = 2): string { + const seen = new WeakSet(); + return JSON.stringify( + obj, + (k, v) => { + if (typeof v === 'object' && v !== null) { + if (seen.has(v)) { + return '[Circular]'; + } + seen.add(v); + } + return v; + }, + space, + ); +} diff --git a/packages/chrome-devtools/src/component/ShareGraph/global.d.ts b/packages/chrome-devtools/src/component/ShareGraph/global.d.ts new file mode 100755 index 00000000000..1b91a873ce6 --- /dev/null +++ b/packages/chrome-devtools/src/component/ShareGraph/global.d.ts @@ -0,0 +1,33 @@ +export interface Shared { + from?: string; + useIn?: string[]; + loaded?: boolean; +} + +export type ShareScopeMap = Record< + string, + Record | Shared> +>; +export type GlobalShareScopeMap = Record; + +export interface NormalizedVersionInfo { + providers: string[]; + consumers: string[]; + loaded: boolean; + instance: string; +} + +export type NormalizedShare = { + versions: Record; +}; +export type Normalized = Record>; // normalized[scope][shareName] + +export interface AppState { + normalized: Normalized; + currentScope: string | null; + currentShare: string | null; + currentVersion: string | null; + level: 1 | 2 | 3; // 1: scope+share, 2: +version, 3: +providers/consumers + mode: 'g6' | 'degrade'; + lastError: string | null; +} diff --git a/packages/chrome-devtools/src/component/ShareGraph/index.tsx b/packages/chrome-devtools/src/component/ShareGraph/index.tsx new file mode 100644 index 00000000000..d747dabfe4a --- /dev/null +++ b/packages/chrome-devtools/src/component/ShareGraph/index.tsx @@ -0,0 +1,1658 @@ +/* eslint-disable max-lines */ +import React, { useState, useEffect, useRef, useCallback } from 'react'; +import G6 from '@antv/g6'; +import type { Graph } from '@antv/g6'; +import { Message } from '@arco-design/web-react'; +import { + normalizeGlobalShare, + validateNormalized, + safeStringify, +} from './adapter'; +import type { AppState, Normalized } from './global'; +import styles from './styles.module.scss'; + +type Level = 1 | 2 | 3; + +const DEFAULT_SHARE_SCOPE = 'default'; +// 定义节点和边的类型 +interface G6Node { + id: string; + label: string; + dataType: 'share' | 'version' | 'consumer' | 'provider' | 'provider-note'; + scope?: string; + share?: string; + version?: string; + consumer?: string; + provider?: string; + instance?: string; + type: 'circle' | 'rect' | 'version-node'; + style: { + fill: string; + stroke: string; + strokeWidth: number; + opacity: number; + cursor: string; + shadowColor?: string; + shadowBlur?: number; + shadowOffsetX?: number; + shadowOffsetY?: number; + lineDash?: number[]; + }; + size: number | [number, number]; + labelCfg: { + position: 'center'; + style: { + fill: string; + fontSize: number; + fontWeight?: string | number; + }; + }; + draggable: boolean; + mass: number; + fx: number | null; + fy: number | null; + x?: number; + y?: number; + instanceCount?: number; +} + +interface G6Edge { + source: string; + target: string; + style: { + stroke: string; + strokeWidth: number; + opacity: number; + endArrow?: { + path: string; + fill: string; + stroke: string; + }; + lineDash?: number[]; + }; + strength?: number; +} + +interface ShareGraphProps { + className?: string; + shareInfo?: Record; +} + +const getFontSize = (loaded: boolean, fontSize?: number) => { + if (fontSize) { + return fontSize; + } + return loaded ? 11 : 10; +}; + +const calcSize = ( + label: string, + loaded: boolean, + base = 1, + fontSize?: number, +) => { + const textWidth = label.length * getFontSize(loaded, fontSize) * base; + return textWidth / 2; +}; + +const ShareGraph: React.FC = ({ className, shareInfo }) => { + // 全局状态 + const [state, setState] = useState({ + normalized: {}, + currentScope: null, + currentShare: null, + currentVersion: null, + level: 1, + mode: 'g6', + lastError: null, + }); + + const [modalVisible, setModalVisible] = useState(false); + const [modalContent, setModalContent] = useState(''); + const [g6Initialized, setG6Initialized] = useState(false); + const [errorMessage, setErrorMessage] = useState(null); + const [isRendering, setIsRendering] = useState(false); + const graphContainerRef = useRef(null); + const graphRef = useRef(null); + + // 初始化G6图形 + const initGraph = useCallback( + ( + container: HTMLDivElement, + onNodeClick: (model: G6Node) => void, + ): Promise => { + return new Promise((resolve, reject) => { + console.log('initGraph 开始'); + + if (!container) { + reject(new Error('容器元素不存在')); + return; + } + + const width = container.clientWidth || 800; + const height = container.clientHeight || 600; + + try { + const graph = new G6.Graph({ + container, + width, + height, + layout: { + type: 'force', + linkDistance: 250, + nodeStrength: -400, + edgeStrength: 0.05, + nodeSize: 60, + minMovement: 0.5, + maxIteration: 1500, + damping: 0.8, + preventOverlap: true, + collideStrength: 0.5, + }, + modes: { + default: ['drag-canvas', 'zoom-canvas', 'drag-node'], + }, + defaultNode: { + type: 'circle', + size: 30, + style: { + fill: '#fff', + stroke: '#cbd5e1', + strokeWidth: 2, + cursor: 'pointer', + shadowColor: 'rgba(0, 0, 0, 0.1)', + shadowBlur: 6, + shadowOffsetX: 2, + shadowOffsetY: 2, + }, + labelCfg: { + position: 'center', + style: { + fontSize: 12, + fill: '#0f172a', + fontWeight: 500, + textAlign: 'center', + textBaseline: 'middle', + }, + }, + draggable: true, + }, + defaultEdge: { + type: 'cubic-horizontal', + style: { + stroke: '#94a3b8', + strokeWidth: 2, + endArrow: { + path: 'M 0,0 L 8,4 L 8,-4 Z', + fill: '#94a3b8', + stroke: '#94a3b8', + }, + shadowColor: 'rgba(148, 163, 184, 0.2)', + shadowBlur: 3, + opacity: 0.8, + }, + }, + fitView: true, + fitViewPadding: 20, + animate: true, + groupByTypes: false, + }); + + // 注册自定义节点,用于显示徽标 + G6.registerNode('version-node', { + draw(cfg, group) { + const { size, color, style, label, instanceCount } = cfg; + const r = (size as number) / 2; + + const { + fill, + stroke, + strokeWidth, + lineDash, + cursor, + opacity, + shadowColor, + shadowBlur, + fontSize, + fontWeight, + } = style || {}; + // 绘制主圆形 + const mainCircle = group.addShape('circle', { + attrs: { + x: 0, + y: 0, + r, + fill: color || fill, + stroke, + strokeWidth, + lineDash, + cursor, + opacity, + shadowColor, + shadowBlur, + }, + }); + + // 绘制标签 + if (label) { + group.addShape('text', { + attrs: { + x: 0, + y: 0, + text: label, + fontSize: fontSize || 10, + fontWeight: fontWeight || 'normal', + fill: '#ffffff', + textAlign: 'center', + textBaseline: 'middle', + }, + }); + } + + // 如果有实例数量,绘制徽标 + if ( + !Number.isNaN(instanceCount) && + (instanceCount as number) > 1 + ) { + const badgeSize = Math.max( + 12, + Math.min(18, 8 + (instanceCount as number)), + ); + const badgeX = r - badgeSize / 2; + const badgeY = -r + badgeSize / 2; + + // 绘制徽标背景 + group.addShape('circle', { + attrs: { + x: badgeX, + y: badgeY, + r: badgeSize / 2, + fill: '#ef4444', + stroke: '#ffffff', + strokeWidth: 1, + opacity: 0.9, + }, + }); + + // 绘制徽标文本 + group.addShape('text', { + attrs: { + x: badgeX, + y: badgeY, + text: String(instanceCount), + fontSize: Math.max(8, Math.min(12, badgeSize / 2)), + fontWeight: 'bold', + fill: '#ffffff', + textAlign: 'center', + textBaseline: 'middle', + }, + }); + } + + return mainCircle; + }, + }); + + // 设置 graphRef.current + graphRef.current = graph; + + // 添加事件监听器 + graph.on( + 'node:click', + (ev: { item?: { getModel?: () => G6Node } }) => { + const model = ev?.item?.getModel?.(); + if (!model) { + return; + } + onNodeClick(model); + }, + ); + + // 直接resolve,不需要等待 + resolve(); + } catch (e) { + console.error('创建 G6 图形失败:', e); + reject(e); + } + }); + }, + [], + ); + + // 安全更新G6数据 + const safeChangeData = useCallback((nodes: G6Node[], edges: G6Edge[]) => { + const graph = graphRef.current; + + if (!graph) { + console.error('graph不可用,直接降级'); + return false; + } + + try { + if (nodes.length > 1200 || edges.length > 2000) { + throw new Error('数据量过大,降级'); + } + + // 获取当前图形数据 + const currentData = graph.save(); + const currentNodes: G6Node[] = (currentData?.nodes as G6Node[]) || []; + + // 检查是否需要更新数据 + const needsUpdate = + nodes.length !== currentNodes.length || + nodes.some((node) => !currentNodes.find((n) => n.id === node.id)); + + if (!needsUpdate) { + console.log('数据未变化,跳过更新'); + return true; + } + + // 为节点设置初始位置,避免聚集在一起 + const optimizedNodes = nodes.map((node) => { + // 根据节点类型设置不同的初始位置 + if (node.dataType === 'share') { + // 第一层级的大节点,按圆形分布 + const shareNodes = nodes.filter((n) => n.dataType === 'share'); + const shareIndex = shareNodes.indexOf(node); + const angle = (shareIndex / shareNodes.length) * Math.PI * 2; + const radius = 300; + return { + ...node, + x: 400 + Math.cos(angle) * radius, + y: 300 + Math.sin(angle) * radius, + }; + } else if (node.dataType === 'version') { + // 版本节点,围绕对应的share节点分布 + const parentNode = nodes.find( + (n) => n.id === `share:${node.scope}:${node.share}`, + ); + if (parentNode) { + const versionNodes = nodes.filter( + (n) => n.dataType === 'version' && n.share === node.share, + ); + const versionIndex = versionNodes.indexOf(node); + const angle = (versionIndex / versionNodes.length) * Math.PI * 2; + const radius = 150; + return { + ...node, + x: (parentNode.x || 0) + Math.cos(angle) * radius, + y: (parentNode.y || 0) + Math.sin(angle) * radius, + }; + } + return { + ...node, + x: 400 + Math.random() * 300 - 150, + y: 300 + Math.random() * 300 - 150, + }; + } else if ( + node.dataType === 'consumer' || + node.dataType === 'provider' + ) { + // 第三层级的提供者和消费者节点,围绕主节点分布 + const parentNode = nodes.find( + (n) => n.dataType === 'share' && n.share === node.share, + ); + if (parentNode) { + const angle = Math.random() * Math.PI * 2; + const radius = 220; + return { + ...node, + x: (parentNode.x || 0) + Math.cos(angle) * radius, + y: (parentNode.y || 0) + Math.sin(angle) * radius, + }; + } + return { + ...node, + x: 400 + Math.random() * 300 - 150, + y: 300 + Math.random() * 300 - 150, + }; + } + + // 默认位置 + return { + ...node, + x: 400 + Math.random() * 300 - 150, + y: 300 + Math.random() * 300 - 150, + }; + }); + + // 使用G6 4.x版本的数据更新方法 + graph.data({ nodes: optimizedNodes, edges, id: 'root' }); + graph.render(); + + // 只在必要时重新计算布局 + if (needsUpdate) { + // 强制重新计算布局 + if (typeof graph.updateLayout === 'function') { + graph.updateLayout({ + type: 'force', + linkDistance: 250, + nodeStrength: -400, + edgeStrength: 0.05, + minMovement: 0.5, + maxIteration: 1500, + damping: 0.8, + preventOverlap: true, + collideStrength: 0.5, + }); + + // 直接适配视图,不延迟 + if (typeof graph.fitView === 'function') { + graph.fitView(30); + } + } + } + + return true; + } catch (e) { + console.error('safeChangeData 降级:', e); + return false; + } + }, []); + + // 第一层级:展示所有share,按shareName分组 + const renderLevel1 = useCallback( + ( + normalized: Normalized, + onlyScope = DEFAULT_SHARE_SCOPE, + ): { nodes: G6Node[]; edges: G6Edge[] } => { + const nodes: G6Node[] = []; + const edges: G6Edge[] = []; + const scopes = onlyScope ? [onlyScope] : Object.keys(normalized || {}); + // 为每个shareName生成一个颜色 + const shareColors: Record = {}; + let colorIndex = 0; + const colors = [ + '#3b82f6', + '#ef4444', + '#10b981', + '#f59e0b', + '#8b5cf6', + '#ec4899', + '#14b8a6', + '#f97316', + '#06b6d4', + '#84cc16', + ]; + + // 收集所有shareName并分配颜色 + for (const scope of scopes) { + const shares = normalized[scope] || {}; + for (const shareName of Object.keys(shares)) { + if (!shareColors[shareName]) { + shareColors[shareName] = colors[colorIndex % colors.length]; + colorIndex++; + } + } + } + + // 创建节点和边 + for (const scope of scopes) { + const shares = normalized[scope] || {}; + for (const [shareName, shareInfo] of Object.entries(shares)) { + const versions = Object.keys(shareInfo?.versions || {}); + const baseColor = shareColors[shareName]; + // 创建大节点(shareName) + nodes.push({ + id: `share:${scope}:${shareName}`, + label: shareName, + dataType: 'share', + scope, + share: shareName, + type: 'circle', + style: { + fill: baseColor, + stroke: baseColor, + strokeWidth: 2, + opacity: 0.9, + cursor: 'pointer', + }, + size: calcSize(shareName, false, 2.2), + labelCfg: { + position: 'center', + style: { + fill: '#ffffff', + fontSize: 12, + fontWeight: 'bold', + }, + }, + draggable: true, + mass: 2, + fx: null, + fy: null, + }); + + // 创建小节点(版本) + versions.forEach((version) => { + const versionInfos = shareInfo.versions[version]; + const instanceCount = versionInfos?.length || 0; + const loaded = versionInfos.some((v) => v.loaded); + + nodes.push({ + id: `version:${scope}:${shareName}:${version}`, + label: version, + dataType: 'version', + scope, + share: shareName, + version, + type: 'version-node', + style: { + fill: baseColor, + stroke: '#ffffff', + strokeWidth: loaded ? 3 : 2, + opacity: loaded ? 0.8 : 0.5, + cursor: 'pointer', + shadowColor: loaded ? baseColor : 'transparent', + shadowBlur: loaded ? 10 : 0, + lineDash: loaded ? undefined : [3, 3], + }, + size: calcSize(version, loaded), + labelCfg: { + position: 'center', + style: { + fill: '#ffffff', + fontSize: getFontSize(loaded), + fontWeight: loaded ? 'bold' : 'normal', + }, + }, + draggable: true, + mass: 1, + fx: null, + fy: null, + instanceCount, + }); + + // 连接大节点和小节点 + edges.push({ + source: `share:${scope}:${shareName}`, + target: `version:${scope}:${shareName}:${version}`, + style: { + stroke: baseColor, + strokeWidth: loaded ? 2 : 1.5, + opacity: loaded ? 0.9 : 0.7, + endArrow: { + path: 'M 0,0 L 6,3 L 6,-3 Z', + fill: baseColor, + stroke: baseColor, + }, + }, + strength: 0.2, + }); + }); + } + } + + // 创建不同组之间的连线(只连接大节点,组成一个圈) + const shareNodes = nodes.filter((n) => n.dataType === 'share'); + for (let i = 0; i < shareNodes.length; i++) { + const currentNode = shareNodes[i]; + const nextNode = shareNodes[(i + 1) % shareNodes.length]; + + edges.push({ + source: currentNode.id, + target: nextNode.id, + style: { + stroke: '#94a3b8', + strokeWidth: 1, + opacity: 0.3, + lineDash: [5, 5], + }, + strength: 0.05, + }); + } + + return { nodes, edges }; + }, + [], + ); + + // 第二层级:展示特定shareName的所有版本(放大显示) + const renderLevel2 = useCallback( + ( + normalized: Normalized, + scope: string, + shareName: string, + ): { nodes: G6Node[]; edges: G6Edge[] } => { + const nodes: G6Node[] = []; + const edges: G6Edge[] = []; + const shareInfo = normalized[scope]?.[shareName]; + if (!shareInfo) { + return { nodes, edges }; + } + + const versions = Object.keys(shareInfo?.versions || {}); + const baseColor = '#3b82f6'; + + // 创建大节点(shareName)- 放大版本 + nodes.push({ + id: `share:${scope}:${shareName}`, + label: shareName, + dataType: 'share', + scope, + share: shareName, + type: 'circle', + style: { + fill: baseColor, + stroke: baseColor, + strokeWidth: 3, + opacity: 0.9, + cursor: 'pointer', + }, + size: calcSize(shareName, false, 2.2), + labelCfg: { + position: 'center', + style: { + fill: '#ffffff', + fontSize: 16, + fontWeight: 'bold', + }, + }, + draggable: true, + mass: 3, + fx: null, + fy: null, + }); + + // 创建小节点(版本)- 放大版本 + versions.forEach((version) => { + const versionInfos = shareInfo.versions[version]; + const instanceCount = versionInfos?.length || 0; + const loaded = versionInfos.some((v) => v.loaded); + + nodes.push({ + id: `version:${scope}:${shareName}:${version}`, + label: version, + dataType: 'version', + scope, + share: shareName, + version, + type: 'version-node', + style: { + fill: baseColor, + stroke: '#ffffff', + strokeWidth: loaded ? 4 : 3, + opacity: loaded ? 1 : 0.6, + cursor: 'pointer', + shadowColor: loaded ? baseColor : 'transparent', + shadowBlur: loaded ? 15 : 0, + lineDash: loaded ? undefined : [4, 4], + }, + size: calcSize(version, loaded), + labelCfg: { + position: 'center', + style: { + fill: '#ffffff', + fontSize: loaded ? 13 : 12, + fontWeight: loaded ? 'bold' : 'normal', + }, + }, + draggable: true, + mass: 2, + fx: null, + fy: null, + instanceCount, + }); + + // 连接大节点和小节点 + edges.push({ + source: `share:${scope}:${shareName}`, + target: `version:${scope}:${shareName}:${version}`, + style: { + stroke: baseColor, + strokeWidth: loaded ? 2.5 : 2, + opacity: loaded ? 0.9 : 0.8, + endArrow: { + path: 'M 0,0 L 8,4 L 8,-4 Z', + fill: baseColor, + stroke: baseColor, + }, + }, + strength: 0.3, + }); + }); + + return { nodes, edges }; + }, + [], + ); + + // 第三层级:展示提供者和消费者关系 + const renderLevel3 = useCallback( + ( + normalized: Normalized, + scope: string, + shareName: string, + version: string, + ): { nodes: G6Node[]; edges: G6Edge[] } => { + const nodes: G6Node[] = []; + const edges: G6Edge[] = []; + const versionInfos = normalized[scope]?.[shareName]?.versions?.[version]; + if ( + !versionInfos || + !Array.isArray(versionInfos) || + versionInfos.length === 0 + ) { + return { nodes, edges }; + } + + // 为每个版本信息创建节点 + versionInfos.forEach((versionInfo) => { + const { instance } = versionInfo; + const labelText = `${shareName}@${version}`; + const fontSize = 14; + const textWidth = labelText.length * fontSize * 0.6; // 估算文本宽度 + const nodeWidth = Math.max(120, textWidth + 20); // 最小宽度120px,加上内边距 + const nodeHeight = Math.max(80, textWidth + 40); // 增加高度以容纳备注 + + // 检查是否加载 + const isLoaded = versionInfo?.loaded || false; + + nodes.push({ + id: `share:${scope}:${shareName}:${instance}`, + label: isLoaded + ? `${shareName}@${version}\n(loaded)` + : `${shareName}@${version}`, + dataType: 'share', + scope, + share: shareName, + version, + instance, + type: 'rect', + style: { + fill: isLoaded ? '#059669' : '#10b981', + stroke: '#ffffff', + strokeWidth: isLoaded ? 4 : 2, + opacity: isLoaded ? 1 : 0.5, + cursor: 'pointer', + lineDash: isLoaded ? undefined : [3, 3], + shadowColor: isLoaded ? '#059669' : 'transparent', + shadowBlur: isLoaded ? 10 : 0, + }, + size: [nodeWidth, nodeHeight], + labelCfg: { + position: 'center', + style: { + fill: '#ffffff', + fontSize, + fontWeight: 'bold', + }, + }, + draggable: true, + mass: 3, + fx: null, + fy: null, + }); + + // 添加备注节点(from: 提供者) + nodes.push({ + id: `provider-note:${scope}:${shareName}:${version}:${instance}`, + label: `from: ${instance}`, + dataType: 'provider-note', + scope, + share: shareName, + version, + instance, + type: 'rect', + style: { + fill: '#ef4444', + stroke: '#ef4444', + strokeWidth: 2, + opacity: 0.8, + cursor: 'pointer', + }, + size: [Math.max(100, instance.length * 8 + 20), 30], + labelCfg: { + position: 'center', + style: { + fill: '#ffffff', + fontSize: 12, + }, + }, + draggable: true, + mass: 2, + fx: null, + fy: null, + }); + + // 连接备注节点到主节点 + edges.push({ + source: `provider-note:${scope}:${shareName}:${version}:${instance}`, + target: `share:${scope}:${shareName}:${instance}`, + style: { + stroke: '#ef4444', + strokeWidth: 3, + opacity: 0.9, + endArrow: { + path: 'M 0,0 L 8,4 L 8,-4 Z', + fill: '#ef4444', + stroke: '#ef4444', + }, + }, + strength: 0.3, + }); + + // 创建消费者节点 + const consumers = versionInfo.consumers || []; + consumers.forEach((consumer, consumerIndex) => { + const fontSize = 12; + const textWidth = consumer.length * fontSize * 0.6; // 估算文本宽度 + const nodeSize = Math.max(50, textWidth + 20); // 最小尺寸50px,加上内边距 + + nodes.push({ + id: `consumer:${scope}:${shareName}:${version}:${instance}:${consumerIndex}`, + label: consumer, + dataType: 'consumer', + scope, + share: shareName, + version, + instance, + consumer, + type: 'circle', + style: { + fill: '#8b5cf6', + stroke: '#8b5cf6', + strokeWidth: 2, + opacity: 0.8, + cursor: 'pointer', + }, + size: nodeSize, + labelCfg: { + position: 'center', + style: { + fill: '#ffffff', + fontSize, + }, + }, + draggable: true, + mass: 1.5, + fx: null, + fy: null, + }); + + // 连接消费者到主节点 + edges.push({ + source: `consumer:${scope}:${shareName}:${version}:${instance}:${consumerIndex}`, + target: `share:${scope}:${shareName}:${instance}`, + style: { + stroke: '#8b5cf6', + strokeWidth: 3, + opacity: 0.9, + endArrow: { + path: 'M 0,0 L 8,4 L 8,-4 Z', + fill: '#8b5cf6', + stroke: '#8b5cf6', + }, + }, + strength: 0.3, + }); + }); + }); + + return { nodes, edges }; + }, + [], + ); + + // 根据状态渲染 - 移到最前面,避免循环依赖 + const renderByState = useCallback( + (currentState: AppState) => { + // 如果正在渲染,跳过 + if (isRendering) { + console.log('正在渲染中,跳过'); + return; + } + + // 检查状态是否真的发生了变化 + if ( + currentState.normalized === state.normalized && + currentState.currentScope === state.currentScope && + currentState.currentShare === state.currentShare && + currentState.currentVersion === state.currentVersion && + currentState.level === state.level + ) { + console.log('状态未变化,跳过渲染'); + return; + } + + try { + console.log('renderByState'); + + // 设置渲染状态 + setIsRendering(true); + + const { normalized } = currentState; + + if (currentState.level === 1) { + const { nodes, edges } = renderLevel1( + normalized, + currentState.currentScope || undefined, + ); + const ok = safeChangeData(nodes, edges); + if (!ok) { + setErrorMessage('图形渲染失败,请检查浏览器控制台获取更多信息'); + return; + } + } else if ( + currentState.level === 2 && + currentState.currentScope && + currentState.currentShare + ) { + const { nodes, edges } = renderLevel2( + normalized, + currentState.currentScope, + currentState.currentShare, + ); + const ok = safeChangeData(nodes, edges); + if (!ok) { + setErrorMessage('图形渲染失败,请检查浏览器控制台获取更多信息'); + return; + } + } else if ( + currentState.level === 3 && + currentState.currentScope && + currentState.currentShare && + currentState.currentVersion + ) { + const { nodes, edges } = renderLevel3( + normalized, + currentState.currentScope, + currentState.currentShare, + currentState.currentVersion, + ); + const ok = safeChangeData(nodes, edges); + if (!ok) { + setErrorMessage('图形渲染失败,请检查浏览器控制台获取更多信息'); + return; + } + } else { + // 状态不完整,回退到第一层级,全局 + const { nodes, edges } = renderLevel1(normalized, undefined); + const ok = safeChangeData(nodes, edges); + if (!ok) { + setErrorMessage('图形渲染失败,请检查浏览器控制台获取更多信息'); + return; + } + } + + // 清除错误信息 + setErrorMessage(null); + } catch (e: unknown) { + const errorMsg = `渲染失败:${(e as Error)?.message}`; + console.error('渲染失败:', e); + setState((prev) => { + const newState = { ...prev, lastError: errorMsg }; + console.log('状态更新(渲染失败):', newState); + return newState; + }); + setErrorMessage(errorMsg); + } finally { + // 重置渲染状态 + setIsRendering(false); + } + }, + [isRendering], + ); + + // 窗口大小调整处理 + useEffect(() => { + const handleResize = () => { + const graph = graphRef.current; + const container = graphContainerRef.current; + + if (graph && container) { + const newW = container.clientWidth; + const newH = container.clientHeight; + if (typeof graph.changeSize === 'function') { + graph.changeSize(newW, newH); + } + } + }; + + window.addEventListener('resize', handleResize); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + // 节点点击处理 + const onNodeClick = useCallback((model: G6Node) => { + try { + const type = model?.dataType; + console.log('onNodeClick'); + + if (type === 'share') { + console.log('节点点击: share', { + scope: model.scope, + share: model.share, + }); + setState((prev) => { + const newState = { + ...prev, + level: 2 as Level, + currentScope: model.scope || null, + currentShare: model.share || null, + currentVersion: null, + }; + console.log('状态更新(share点击):', newState); + return newState; + }); + + // 确保视图居中 + setTimeout(() => { + const graph = graphRef.current; + if (graph && typeof graph.fitView === 'function') { + graph.fitView(30); + } + }, 100); + } else if (type === 'version') { + console.log('节点点击: version', { + scope: model.scope, + share: model.share, + version: model.version, + }); + setState((prev) => { + const newState = { + ...prev, + level: 3 as Level, + currentScope: model.scope || null, + currentShare: model.share || null, + currentVersion: model.version || null, + }; + console.log('状态更新(version点击):', newState); + return newState; + }); + + // 确保视图居中 + setTimeout(() => { + const graph = graphRef.current; + if (graph && typeof graph.fitView === 'function') { + graph.fitView(30); + } + }, 100); + } + } catch (e: unknown) { + const errorMsg = `节点点击处理失败:${(e as Error)?.message}`; + console.error('节点点击处理失败:', e); + setState((prev) => { + const newState = { + ...prev, + lastError: errorMsg, + }; + console.log('状态更新(节点点击错误):', newState); + return newState; + }); + // 使用函数形式获取最新的state.mode + setState((currentState) => { + return currentState; + }); + } + }, []); + + // 面包屑点击处理 + const handleBreadcrumbClick = useCallback( + ( + level: string, + scope?: string | null, + share?: string | null, + version?: string | null, + ) => { + console.log('面包屑点击:', { level, scope, share, version }); + + if (level === 'all') { + setState((prev) => { + const newState = { + ...prev, + level: 1 as Level, + currentShare: null, + currentVersion: null, + }; + console.log('状态更新(面包屑-all):', newState); + return newState; + }); + + // 确保视图居中 + setTimeout(() => { + const graph = graphRef.current; + if (graph && typeof graph.fitView === 'function') { + graph.fitView(30); + } + }, 100); + } else if (level === 'scope') { + setState((prev) => { + const newState = { + ...prev, + level: 1 as Level, + currentScope: scope || null, + currentShare: null, + currentVersion: null, + }; + console.log('状态更新(面包屑-scope):', newState); + return newState; + }); + + // 确保视图居中 + setTimeout(() => { + const graph = graphRef.current; + if (graph && typeof graph.fitView === 'function') { + graph.fitView(30); + } + }, 100); + } else if (level === 'share') { + setState((prev) => { + const newState = { + ...prev, + level: 2 as Level, + currentScope: scope || null, + currentShare: share || null, + currentVersion: null, + }; + console.log('状态更新(面包屑-share):', newState); + return newState; + }); + + // 确保视图居中 + setTimeout(() => { + const graph = graphRef.current; + if (graph && typeof graph.fitView === 'function') { + graph.fitView(30); + } + }, 100); + } else if (level === 'version') { + setState((prev) => { + const newState = { + ...prev, + level: 3 as Level, + currentScope: scope || null, + currentShare: share || null, + currentVersion: version || null, + }; + console.log('状态更新(面包屑-version):', newState); + return newState; + }); + + // 确保视图居中 + setTimeout(() => { + const graph = graphRef.current; + if (graph && typeof graph.fitView === 'function') { + graph.fitView(30); + } + }, 100); + } + }, + [], + ); + + // 初始化G6 + useEffect(() => { + // 初始化G6,React的useEffect会在DOM渲染完成后自动执行 + (async () => { + try { + console.log('useEffect onNodeClick'); + // 检查容器是否存在 + if (!graphContainerRef.current) { + console.error('找不到容器元素: graphContainer'); + setState((prev) => { + const newState = { + ...prev, + lastError: '找不到容器元素: graphContainer', + }; + console.log('状态更新(找不到容器元素):', newState); + return newState; + }); + setErrorMessage('找不到容器元素: graphContainer'); + return; + } + + await initGraph(graphContainerRef.current, onNodeClick); + console.log('G6初始化成功'); + setG6Initialized(true); + + // G6初始化完成后,加载数据 + try { + if (!shareInfo) { + throw new Error('未提供示例数据'); + } + + console.log('开始加载shareInfo数据'); + const normalized = normalizeGlobalShare(shareInfo); + if (!validateNormalized(normalized)) { + throw new Error( + '示例数据校验失败:缺少有效的 scope/share/version 结构', + ); + } + + // 直接渲染,不触发状态更新 + const { nodes, edges } = renderLevel1( + normalized, + DEFAULT_SHARE_SCOPE, + ); + safeChangeData(nodes, edges); + + // 确保节点在视图中间 + setTimeout(() => { + const graph = graphRef.current; + if (graph && typeof graph.fitView === 'function') { + graph.fitView(30); + } + }, 50); + + // 直接更新状态,不延迟 + setState((prev) => { + const newState: AppState = { + ...prev, + normalized, + lastError: null, + level: 1, + currentScope: null, + currentShare: null, + currentVersion: null, + }; + console.log('状态更新(G6初始化后加载数据):', newState); + return newState; + }); + } catch (e: unknown) { + const errorMsg = `初始示例数据加载失败:${(e as Error)?.message}`; + console.error('初始示例数据加载失败:', e); + setState((prev) => { + const newState = { ...prev, lastError: errorMsg }; + console.log('状态更新(初始示例数据加载失败):', newState); + return newState; + }); + } + } catch (e: unknown) { + const errorMsg = `G6初始化失败:${(e as Error)?.message}`; + console.error('G6初始化失败:', e); + setState((prev) => { + const newState = { + ...prev, + lastError: errorMsg, + }; + console.log('状态更新(G6初始化失败):', newState); + return newState; + }); + setErrorMessage(errorMsg); + } + })(); + }, [onNodeClick, renderLevel1, safeChangeData, shareInfo]); + + // 当状态变化时重新渲染 + useEffect(() => { + if (state.normalized && g6Initialized) { + renderByState(state); + } + }, [ + state.normalized, + state.currentScope, + state.currentShare, + state.currentVersion, + state.level, + g6Initialized, + renderByState, + ]); + + // ShareScope选择器变化处理 + const handleScopeChange = (e: React.ChangeEvent) => { + try { + console.log('handleScopeChange'); + + const selectedScope = e.target.value; + console.log('ShareScope选择器变化:', selectedScope); + + const newState = { + ...state, + currentScope: + selectedScope === DEFAULT_SHARE_SCOPE ? null : selectedScope, + currentShare: null, + currentVersion: null, + level: 1 as Level, + }; + + console.log('状态更新(ShareScope选择器变化):', newState); + setState(newState); + } catch (e: unknown) { + const errorMsg = `切换Scope失败:${(e as Error)?.message}`; + console.error('切换Scope失败:', e); + setState((prev) => { + const newState = { ...prev, lastError: errorMsg }; + console.log('状态更新(切换Scope失败):', newState); + return newState; + }); + } + }; + + // ShareName选择器变化处理 + const handleShareNameChange = (e: React.ChangeEvent) => { + try { + console.log('handleShareNameChange'); + + const selectedShareName = e.target.value; + console.log('ShareName选择器变化:', selectedShareName); + + if (!selectedShareName) { + // 如果选择了空值,回到第一层级 + const newState = { + ...state, + currentShare: null, + currentVersion: null, + level: 1 as Level, + }; + + console.log('状态更新(ShareName选择器变化):', newState); + setState(newState); + // 确保视图居中 + setTimeout(() => { + const graph = graphRef.current; + if (graph && typeof graph.fitView === 'function') { + graph.fitView(30); + } + }, 100); + return; + } + + // 如果选择了shareName,需要确定是哪个scope + let targetScope = state.currentScope; + + // 如果没有选择scope,需要查找包含该shareName的scope + if (!targetScope) { + Object.keys(state.normalized).forEach((scope) => { + if (state.normalized[scope]?.[selectedShareName]) { + targetScope = scope; + } + }); + } + + // 如果选择了shareName,进入第二层级 + const newState = { + ...state, + currentScope: targetScope, + currentShare: selectedShareName, + currentVersion: null, + level: 2 as Level, + }; + + console.log('状态更新(ShareName选择器变化):', newState); + setState(newState); + // 确保视图居中 + setTimeout(() => { + const graph = graphRef.current; + if (graph && typeof graph.fitView === 'function') { + graph.fitView(30); + } + }, 100); + } catch (e: unknown) { + const errorMsg = `切换ShareName失败:${(e as Error)?.message}`; + console.error('切换ShareName失败:', e); + setState((prev) => { + const newState = { ...prev, lastError: errorMsg }; + console.log('状态更新(切换ShareName失败):', newState); + return newState; + }); + // 确保视图居中 + setTimeout(() => { + const graph = graphRef.current; + if (graph && typeof graph.fitView === 'function') { + graph.fitView(30); + } + }, 100); + } + }; + + // 复制路径 + const handleCopyPath = async () => { + try { + console.log('handleCopyPath'); + + const base = '__FEDERATION__.__SHARE__'; + const segs: string[] = []; + if (state.currentScope) { + segs.push(`['${state.currentScope}']`); + } + if (state.currentShare) { + segs.push(`['${state.currentShare}']`); + } + if (state.currentVersion) { + segs.push(`['${state.currentVersion}']`); + } + const text = base + segs.join(''); + + await navigator.clipboard.writeText(text); + + // 显示成功提示 + Message.success({ + content: + '路径已复制到剪贴板!您可以在控制台粘贴此路径查看具体的 share 信息', + duration: 3000, + }); + } catch (e: unknown) { + const errorMsg = `复制失败:${(e as Error)?.message}`; + setState((prev) => ({ ...prev, lastError: errorMsg })); + + // 显示错误提示 + Message.error({ + content: errorMsg, + duration: 3000, + }); + } + }; + + // More按钮点击 + const handleMoreClick = () => { + try { + console.log('handleMoreClick'); + if ( + state.level !== 3 || + !state.currentScope || + !state.currentShare || + !state.currentVersion + ) { + return; + } + const info = + state.normalized[state.currentScope][state.currentShare].versions[ + state.currentVersion + ]; + const content = safeStringify(info, 2); + setModalContent(content); + setModalVisible(true); + } catch (e: unknown) { + const errorMsg = `More 弹窗展示失败:${(e as Error)?.message}`; + setState((prev) => ({ ...prev, lastError: errorMsg })); + } + }; + + // 关闭弹窗 + const handleCloseModal = () => { + console.log('handleCloseModal'); + + setModalVisible(false); + }; + + // 生成面包屑 + const generateBreadcrumb = () => { + const parts = []; + parts.push( + handleBreadcrumbClick('all')} + > + 全部 + , + ); + + if (state.currentShare) { + parts.push(); + parts.push( + + handleBreadcrumbClick( + 'share', + state.currentScope, + state.currentShare, + ) + } + > + {state.currentShare} + , + ); + } + + if (state.currentVersion) { + parts.push(); + parts.push( + + handleBreadcrumbClick( + 'version', + state.currentScope, + state.currentShare, + state.currentVersion, + ) + } + > + {state.currentVersion} + , + ); + } + + return parts; + }; + + // 获取ShareScope选项 + const getScopeOptions = () => { + const scopes = Object.keys(state.normalized); + return scopes; + }; + + // 获取ShareName选项 + const getShareNameOptions = () => { + // 如果没有选择ShareScope,返回所有ShareName选项 + if (!state.currentScope) { + const allShareNames: string[] = []; + Object.keys(state.normalized).forEach((scope) => { + const shareNames = Object.keys(state.normalized[scope] || {}); + allShareNames.push(...shareNames); + }); + // 去重 + return [...new Set(allShareNames)]; + } + + const shareNames = Object.keys(state.normalized[state.currentScope] || {}); + return shareNames; + }; + return ( +
+ {/* 如果没有shareInfo数据,显示提示信息 */} + {!shareInfo && ( +
+

No ShareInfo Detected

+
+ )} + + {/* 左侧主画布区域 */} +
+
+
+
+ + +
+
+ + +
+ +
+
+ + {state.level === 3 && ( + + )} +
+
+
+ {errorMessage && ( +
+
+

Oops ! Something wrong...

+

{errorMessage}

+
+
+ )} +
+
+ + {/* 弹窗 */} + {modalVisible && ( +
+
e.stopPropagation()} + > +
+

详细信息

+ +
+
+
{modalContent}
+
+
+
+ )} +
+ ); +}; + +export default ShareGraph; diff --git a/packages/chrome-devtools/src/component/ShareGraph/styles.module.scss b/packages/chrome-devtools/src/component/ShareGraph/styles.module.scss new file mode 100755 index 00000000000..83e2d0576d8 --- /dev/null +++ b/packages/chrome-devtools/src/component/ShareGraph/styles.module.scss @@ -0,0 +1,356 @@ +/* 现代风格样式与节点类型区分 */ +:root { + --color-scope: #0ea5e9; /* 天蓝 */ + --color-share: #22c55e; /* 绿色 */ + --color-version: #f59e0b; /* 橙色 */ + --color-provider: #fb7185; /* 粉红 */ + --color-consumer: #8b5cf6; /* 紫色 */ + --color-border: #e2e8f0; + --color-muted: #64748b; +} + +.nodeScope { + background: #e0f2fe; + border: 1px solid var(--color-scope); +} + +.nodeShare { + background: #dcfce7; + border: 1px solid var(--color-share); +} + +.nodeVersion { + background: #fef3c7; + border: 1px solid var(--color-version); +} + +.nodeProvider { + background: #ffe4e6; + border: 1px solid var(--color-provider); +} + +.nodeConsumer { + background: #ede9fe; + border: 1px solid var(--color-consumer); +} + +.card { + border: 1px solid var(--color-border); + border-radius: 10px; + padding: 8px; + background: white; + + h4 { + margin: 0 0 6px; + } +} + +.overlayError { + position: absolute; + right: 12px; + top: 12px; + background: rgba(244, 63, 94, 0.08); + color: #be123c; + border: 1px solid #fecaca; + border-radius: 8px; + padding: 6px 8px; + font-size: 12px; + max-width: 60%; +} + +.degradeList { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 10px; +} + +.degradeCol { + display: flex; + flex-direction: column; + gap: 8px; +} + +.badge { + display: inline-block; + padding: 2px 6px; + border-radius: 6px; + font-size: 12px; + color: #0f172a; + background: #f1f5f9; + border: 1px solid var(--color-border); +} + +.link { + color: #2563eb; + cursor: pointer; +} + +/* App组件样式 */ +.appContainer { + display: flex; + height: 100vh; + background: #f7f8fa; +} + +.noDataContainer { + display: flex; + align-items: center; + justify-content: center; + height: 100vh; + width: 100%; + + h2 { + color: #64748b; + font-size: 24px; + font-weight: 500; + } +} + +.mainContent { + flex: 1; + display: flex; + flex-direction: column; + padding: 12px; + gap: 12px; + width: 100%; +} + +.header { + display: flex; + align-items: center; + justify-content: space-between; +} + +.headerLeft { + display: flex; + align-items: center; + gap: 12px; +} + +.scopeSelector { + display: flex; + align-items: center; + gap: 8px; + + label { + font-size: 14px; + color: #475569; + } + + select { + padding: 6px 8px; + border: 1px solid #e2e8f0; + border-radius: 6px; + background: white; + cursor: pointer; + } +} + +.shareNameSelector { + display: flex; + align-items: center; + gap: 8px; + + label { + font-size: 14px; + color: #475569; + } + + select { + padding: 6px 8px; + border: 1px solid #e2e8f0; + border-radius: 6px; + background: white; + cursor: pointer; + + &:disabled { + background-color: #f1f5f9; + color: #6b7280; + cursor: not-allowed; + } + } +} + +.breadcrumbNav { + display: flex; + gap: 8px; + flex-wrap: wrap; +} + +.crumb { + color: #2563eb; + cursor: pointer; +} + +.headerRight { + display: flex; + align-items: center; + gap: 8px; +} + +.btn { + padding: 8px 12px; + border: 1px solid #e2e8f0; + background: white; + border-radius: 8px; + cursor: pointer; +} + +.btnPrimary { + background: #eef2ff; + color: #3730a3; +} + +.statusBar { + font-size: 12px; + color: #475569; +} + +.graphContainer { + flex: 1; + background: white; + border: 1px solid #e2e8f0; + border-radius: 12px; + position: relative; + overflow: hidden; +} + +.sidebar { + width: 380px; + border-left: 1px solid #e2e8f0; + background: white; + padding: 12px; + display: flex; + flex-direction: column; + gap: 12px; + + h3 { + margin: 0; + font-weight: 600; + } +} + +.buttonGroup { + display: flex; + gap: 8px; +} + +.textarea { + width: 100%; + height: 200px; + border: 1px solid #e2e8f0; + border-radius: 6px; + padding: 8px; + font-family: monospace; + font-size: 12px; + resize: vertical; +} + +.modalOverlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; +} + +.modalContent { + background: white; + border-radius: 12px; + width: 80%; + max-width: 800px; + max-height: 80%; + display: flex; + flex-direction: column; + overflow: hidden; + color: #7195c6; +} + +.modalHeader { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px; + border-bottom: 1px solid #e2e8f0; +} + +.modalTitle { + margin: 0; + font-size: 16px; + font-weight: 600; +} + +.modalClose { + background: none; + border: none; + font-size: 20px; + cursor: pointer; + color: #64748b; +} + +.modalBody { + padding: 16px; + overflow-y: auto; + flex: 1; +} + +.modalJson { + background: #f8fafc; + border: 1px solid #e2e8f0; + border-radius: 6px; + padding: 12px; + font-family: monospace; + font-size: 12px; + white-space: pre-wrap; + overflow-x: auto; +} + +/* 新的App布局样式 */ +.appLayout { + display: flex; + flex-direction: column; + height: 100vh; + font-family: Arial, sans-serif; +} + +.appHeader { + padding: 15px 20px; + background-color: #f0f0f0; + border-bottom: 1px solid #ddd; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + + h1 { + margin: 0; + font-size: 24px; + color: #333; + } +} + +.appMain { + flex: 1; + overflow: hidden; +} + +/* 错误信息样式 */ +.errorContainer { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + font-size: 24px; + color: #64748b; +} + +.errorTitle { + margin: 0 0 16px; +} + +.errorMessage { + margin: 0; + color: #94a3b8; +} diff --git a/packages/chrome-devtools/src/index.tsx b/packages/chrome-devtools/src/index.tsx index 3d7c999a84f..de949d3db64 100644 --- a/packages/chrome-devtools/src/index.tsx +++ b/packages/chrome-devtools/src/index.tsx @@ -1,5 +1,5 @@ import { createRoot } from 'react-dom/client'; - +import '@arco-design/web-react/es/_util/react-19-adapter'; import App from './App'; (async () => { diff --git a/packages/chrome-devtools/src/template/constant.ts b/packages/chrome-devtools/src/template/constant.ts index 9ad3c25c54d..d5c592e42a3 100644 --- a/packages/chrome-devtools/src/template/constant.ts +++ b/packages/chrome-devtools/src/template/constant.ts @@ -11,11 +11,7 @@ export const defaultDataItem = { }; export const defaultModuleData = { - proxyFormField: [ - { - ...defaultDataItem, - }, - ], + proxyFormField: [], }; export const statusInfo: Record< diff --git a/packages/chrome-devtools/src/utils/chrome/index.ts b/packages/chrome-devtools/src/utils/chrome/index.ts index 7dd70aa7d70..7bf823e8150 100644 --- a/packages/chrome-devtools/src/utils/chrome/index.ts +++ b/packages/chrome-devtools/src/utils/chrome/index.ts @@ -22,6 +22,33 @@ export const TabInfo = { currentTabId: 0, }; +export const setTargetTab = (tab?: chrome.tabs.Tab | null) => { + if (!tab || typeof tab.id !== 'number') { + return; + } + window.targetTab = tab; + TabInfo.currentTabId = tab.id; +}; + +export const syncActiveTab = async (tabId?: number) => { + try { + if (typeof tabId === 'number') { + const tab = await chrome.tabs.get(tabId); + setTargetTab(tab); + return tab; + } + const [activeTab] = await getTabs({ + active: true, + lastFocusedWindow: true, + }); + setTargetTab(activeTab); + return activeTab; + } catch (error) { + console.warn('[Module Federation Devtools] syncActiveTab failed', error); + return undefined; + } +}; + export function getCurrentTabId() { return TabInfo.currentTabId; } @@ -41,7 +68,7 @@ export function getInspectWindowTabId() { const target = tabs.find( (tab: chrome.tabs.Tab) => tab.id === tabId, ); - window.targetTab = target as chrome.tabs.Tab; + setTargetTab(target as chrome.tabs.Tab); }); console.log( 'chrome.devtools.inspectedWindow.tabId', @@ -67,49 +94,68 @@ export function getInspectWindowTabId() { }); } +export const refreshModuleInfo = async () => { + if (typeof window !== 'undefined' && window.__FEDERATION__?.moduleInfo) { + // noop - consumers can synchronise from existing cache + } + await sleep(50); + const postMessageStartUrl = getUrl('post-message-start.js'); + await injectScript(injectPostMessage, false, postMessageStartUrl); +}; + export const getGlobalModuleInfo = async ( - callback: React.Dispatch>, + callback: (moduleInfo: GlobalModuleInfo) => void, ) => { + if (typeof window !== 'undefined' && window.__FEDERATION__?.moduleInfo) { + callback( + JSON.parse( + JSON.stringify(window.__FEDERATION__?.moduleInfo), + ) as GlobalModuleInfo, + ); + } await sleep(300); - chrome.runtime.onMessage.addListener( - (message: { origin: string; data: any }) => { - const { origin, data } = message; + const listener = (message: { origin: string; data: any }) => { + const { data } = message; - if (!data || data?.appInfos) { - return; - } - if (!window?.__FEDERATION__) { - definePropertyGlobalVal(window, '__FEDERATION__', {}); - definePropertyGlobalVal(window, '__VMOK__', window.__FEDERATION__); - } - window.__FEDERATION__.originModuleInfo = JSON.parse( - JSON.stringify(data?.moduleInfo), + if (!data || data?.appInfos) { + return; + } + if (!window?.__FEDERATION__) { + definePropertyGlobalVal(window, '__FEDERATION__', {}); + definePropertyGlobalVal(window, '__VMOK__', window.__FEDERATION__); + } + window.__FEDERATION__.originModuleInfo = JSON.parse( + JSON.stringify(data?.moduleInfo), + ); + if (data?.updateModule) { + const moduleIds = Object.keys(window.__FEDERATION__.originModuleInfo); + const shouldUpdate = !moduleIds.some((id) => + id.includes(data.updateModule.name), ); - if (data?.updateModule) { - const moduleIds = Object.keys(window.__FEDERATION__.originModuleInfo); - const shouldUpdate = !moduleIds.some((id) => - id.includes(data.updateModule.name), - ); - if (shouldUpdate) { - const destination = - data.updateModule.entry || data.updateModule.version; - window.__FEDERATION__.originModuleInfo[ - `${data.updateModule.name}:${destination}` - ] = { - remoteEntry: destination, - version: destination, - }; - } + if (shouldUpdate) { + const destination = + data.updateModule.entry || data.updateModule.version; + window.__FEDERATION__.originModuleInfo[ + `${data.updateModule.name}:${destination}` + ] = { + remoteEntry: destination, + version: destination, + }; } - window.__FEDERATION__.moduleInfo = JSON.parse( - JSON.stringify(window.__FEDERATION__.originModuleInfo), - ); - callback(window.__FEDERATION__.moduleInfo); - }, - ); - const postMessageStartUrl = getUrl('post-message-start.js'); - await injectScript(injectPostMessage, false, postMessageStartUrl); + } + if (data?.share) { + window.__FEDERATION__.__SHARE__ = data.share; + } + window.__FEDERATION__.moduleInfo = JSON.parse( + JSON.stringify(window.__FEDERATION__.originModuleInfo), + ); + console.log('getGlobalModuleInfo window', window.__FEDERATION__); + callback(window.__FEDERATION__.moduleInfo); + }; + chrome.runtime.onMessage.addListener(listener); + await refreshModuleInfo(); + return () => chrome.runtime.onMessage.removeListener(listener); }; export const getTabs = (queryOptions = {}) => chrome.tabs.query(queryOptions); @@ -135,11 +181,16 @@ export const injectScript = async ( world: world ? 'MAIN' : 'ISOLATED', args, }) - .then(() => { + .then((results) => { console.log('InjectScript success, excuteScript:', args); + if (Array.isArray(results) && results.length) { + return results[0]?.result; + } + return undefined; }) .catch((e) => { console.log(e, 'InjectScript fail, excuteScript:', args); + return undefined; }); }; diff --git a/packages/chrome-devtools/src/utils/chrome/messages.ts b/packages/chrome-devtools/src/utils/chrome/messages.ts new file mode 100644 index 00000000000..aacda8b7b2c --- /dev/null +++ b/packages/chrome-devtools/src/utils/chrome/messages.ts @@ -0,0 +1,2 @@ +export const MESSAGE_OPEN_SIDE_PANEL = 'mf-devtools/open-side-panel'; +export const MESSAGE_ACTIVE_TAB_CHANGED = 'mf-devtools/active-tab-changed'; diff --git a/packages/chrome-devtools/src/utils/chrome/post-message-listener.ts b/packages/chrome-devtools/src/utils/chrome/post-message-listener.ts index c25d7e9f27b..c4c0406872d 100644 --- a/packages/chrome-devtools/src/utils/chrome/post-message-listener.ts +++ b/packages/chrome-devtools/src/utils/chrome/post-message-listener.ts @@ -13,6 +13,7 @@ if (window.moduleHandler) { data: { moduleInfo: data.moduleInfo, updateModule: data.updateModule, + share: data.share, }, }) .catch(() => { diff --git a/packages/chrome-devtools/src/utils/chrome/post-message-start.ts b/packages/chrome-devtools/src/utils/chrome/post-message-start.ts index 0c683cfc9e9..04dcd7ba6dd 100644 --- a/packages/chrome-devtools/src/utils/chrome/post-message-start.ts +++ b/packages/chrome-devtools/src/utils/chrome/post-message-start.ts @@ -4,6 +4,14 @@ const moduleInfo = window?.__FEDERATION__?.moduleInfo; window.postMessage( { moduleInfo, + share: JSON.parse( + JSON.stringify(window?.__FEDERATION__?.__SHARE__, (_key, value) => { + if (typeof value === 'function') { + return 'Function'; + } + return value; + }), + ), }, '*', ); diff --git a/packages/chrome-devtools/src/utils/chrome/post-message.ts b/packages/chrome-devtools/src/utils/chrome/post-message.ts index b2a3be34272..bfe8efbe50d 100644 --- a/packages/chrome-devtools/src/utils/chrome/post-message.ts +++ b/packages/chrome-devtools/src/utils/chrome/post-message.ts @@ -8,6 +8,7 @@ const getModuleInfo = (): ModuleFederationRuntimePlugin => { name: 'mf-devtool-getModuleInfo-plugin', loadRemoteSnapshot({ options, moduleInfo, remoteSnapshot, ...res }) { const globalSnapshot = helpers.global.getGlobalSnapshot(); + if (!options || options.inBrowser) { window.postMessage( { diff --git a/packages/chrome-devtools/src/utils/chrome/storage.ts b/packages/chrome-devtools/src/utils/chrome/storage.ts index 5638475d1e7..ec573176100 100644 --- a/packages/chrome-devtools/src/utils/chrome/storage.ts +++ b/packages/chrome-devtools/src/utils/chrome/storage.ts @@ -3,6 +3,7 @@ import { removeLocalStorageKey, removeLocalStorage, setLocalStorage, + getLocalStorage, } from '../sdk'; import { injectScript } from './index'; @@ -17,3 +18,6 @@ export const removeStorage = async (...args: any[]) => export const setStorage = async (...args: any[]) => injectScript(setLocalStorage, false, ...args); + +export const getStorageValue = async (...args: any[]) => + injectScript(getLocalStorage, false, ...args); diff --git a/packages/chrome-devtools/src/utils/sdk/index.ts b/packages/chrome-devtools/src/utils/sdk/index.ts index fd40cbe0887..d039146e91d 100644 --- a/packages/chrome-devtools/src/utils/sdk/index.ts +++ b/packages/chrome-devtools/src/utils/sdk/index.ts @@ -4,6 +4,15 @@ export const setLocalStorage = (key: string, value: any) => { localStorage.setItem(key, value); }; +export const getLocalStorage = (key: string) => { + try { + return localStorage.getItem(key); + } catch (error) { + console.warn('[MF Devtools] getLocalStorage failed', error); + return null; + } +}; + export const removeLocalStorage = (key: string) => { const data = localStorage.getItem(key); if (data) { diff --git a/packages/chrome-devtools/src/utils/types/common.ts b/packages/chrome-devtools/src/utils/types/common.ts index abba5b23d4a..4b0a994f52e 100644 --- a/packages/chrome-devtools/src/utils/types/common.ts +++ b/packages/chrome-devtools/src/utils/types/common.ts @@ -1,4 +1,5 @@ import type { ReactNode } from 'react'; +import type { GlobalModuleInfo } from '@module-federation/sdk'; import { getModuleInfo } from '../index'; export interface FormItemStatus { @@ -16,4 +17,6 @@ export interface RootComponentProps { handleProxyAddress?: (address: string) => string; customValueValidate?: (schema: string) => boolean; headerSlot?: ReactNode; + onModuleInfoChange?: (moduleInfo: GlobalModuleInfo) => void; + onModuleInfoReset?: () => void; } diff --git a/packages/chrome-devtools/src/worker/index.ts b/packages/chrome-devtools/src/worker/index.ts index dfd2a01a89b..6d2abe38248 100644 --- a/packages/chrome-devtools/src/worker/index.ts +++ b/packages/chrome-devtools/src/worker/index.ts @@ -1 +1,141 @@ -console.log('Module Federation Worker'); +import { + MESSAGE_ACTIVE_TAB_CHANGED, + MESSAGE_OPEN_SIDE_PANEL, +} from '../utils/chrome/messages'; + +const SIDE_PANEL_PATH = 'html/main/index.html'; + +const getSidePanel = () => (chrome as any)?.sidePanel; + +const resolveTabId = async (tabId?: number) => { + if (typeof tabId === 'number') { + return tabId; + } + const [activeTab] = await chrome.tabs.query({ + active: true, + lastFocusedWindow: true, + }); + return activeTab?.id; +}; + +const broadcastActiveTab = (tabId: number) => { + try { + chrome.runtime.sendMessage({ + type: MESSAGE_ACTIVE_TAB_CHANGED, + tabId, + }); + } catch (error) { + console.warn( + '[Module Federation Devtools] Failed to broadcast active tab', + error, + ); + } +}; + +const openSidePanel = async (tabId?: number) => { + const sidePanel = getSidePanel(); + if (!sidePanel) { + throw new Error('sidePanel api not available'); + } + + const targetTabId = await resolveTabId(tabId); + if (typeof targetTabId !== 'number') { + throw new Error('No active tab available'); + } + + await sidePanel.setOptions({ + tabId: targetTabId, + path: SIDE_PANEL_PATH, + enabled: true, + }); + + if (sidePanel.open) { + await sidePanel.open({ tabId: targetTabId }); + } + broadcastActiveTab(targetTabId); + + if (sidePanel.getOptions) { + try { + const options = await sidePanel.getOptions({ tabId: targetTabId }); + broadcastActiveTab(targetTabId); + return options; + } catch (error) { + console.warn('[Module Federation Devtools] getOptions failed', error); + } + } + + return { + path: SIDE_PANEL_PATH, + enabled: true, + }; +}; + +chrome.runtime.onInstalled.addListener(() => { + const sidePanel = getSidePanel(); + if (sidePanel?.setPanelBehavior) { + sidePanel + .setPanelBehavior({ openPanelOnActionClick: true }) + .catch((error: unknown) => { + console.warn( + '[Module Federation Devtools] setPanelBehavior failed', + error, + ); + }); + } +}); + +chrome.action.onClicked.addListener(async (tab) => { + try { + await openSidePanel(tab.id); + } catch (error) { + console.warn( + '[Module Federation Devtools] Failed to open side panel', + error, + ); + } +}); + +chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { + if (message?.type === MESSAGE_OPEN_SIDE_PANEL) { + openSidePanel(message.tabId) + .then((options) => sendResponse({ ok: true, options })) + .catch((error: unknown) => + sendResponse({ ok: false, message: String(error) }), + ); + return true; + } + return undefined; +}); + +chrome.tabs.onActivated.addListener(async (activeInfo) => { + const tabId = activeInfo?.tabId; + if (typeof tabId !== 'number') { + return; + } + try { + broadcastActiveTab(tabId); + } catch (error) { + console.warn( + '[Module Federation Devtools] Failed to handle tab activation', + error, + ); + } +}); + +chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { + if (changeInfo.status !== 'complete') { + return; + } + if (tab?.active) { + try { + broadcastActiveTab(tabId); + } catch (error) { + console.warn( + '[Module Federation Devtools] Failed to handle tab update', + error, + ); + } + } +}); + +console.log('Module Federation Worker ready'); diff --git a/packages/runtime-core/src/core.ts b/packages/runtime-core/src/core.ts index 98d481bf9ed..283310f0928 100644 --- a/packages/runtime-core/src/core.ts +++ b/packages/runtime-core/src/core.ts @@ -78,7 +78,7 @@ export class ModuleFederation { remoteInfo: RemoteInfo; remoteEntryExports: RemoteEntryExports; origin: ModuleFederation; - id: string; + id?: string; remoteSnapshot?: ModuleInfo; }>('initContainer'), }); diff --git a/packages/runtime-core/src/module/index.ts b/packages/runtime-core/src/module/index.ts index 313817040aa..5154a4d55f0 100644 --- a/packages/runtime-core/src/module/index.ts +++ b/packages/runtime-core/src/module/index.ts @@ -36,9 +36,7 @@ class Module { return this.remoteEntryExports; } - let remoteEntryExports; - - remoteEntryExports = await getRemoteEntry({ + const remoteEntryExports = await getRemoteEntry({ origin: this.host, remoteInfo: this.remoteInfo, remoteEntryExports: this.remoteEntryExports, @@ -54,14 +52,8 @@ class Module { } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - async get( - id: string, - expose: string, - options?: { loadFactory?: boolean }, - remoteSnapshot?: ModuleInfo, - ) { - const { loadFactory = true } = options || { loadFactory: true }; + async init(id?: string, remoteSnapshot?: ModuleInfo) { // Get remoteEntry.js const remoteEntryExports = await this.getEntry(); @@ -133,6 +125,19 @@ class Module { }); } + return remoteEntryExports; + } + + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types + async get( + id: string, + expose: string, + options?: { loadFactory?: boolean }, + remoteSnapshot?: ModuleInfo, + ) { + const { loadFactory = true } = options || { loadFactory: true }; + + const remoteEntryExports = await this.init(id, remoteSnapshot); this.lib = remoteEntryExports; this.inited = true; diff --git a/packages/runtime-core/src/shared/index.ts b/packages/runtime-core/src/shared/index.ts index a1c24b6ce2a..610008e9b00 100644 --- a/packages/runtime-core/src/shared/index.ts +++ b/packages/runtime-core/src/shared/index.ts @@ -301,25 +301,7 @@ export class SharedHandler { const { module } = await host.remoteHandler.getRemoteModuleAndOptions({ id: key, }); - if (module.getEntry) { - let remoteEntryExports: RemoteEntryExports; - try { - remoteEntryExports = await module.getEntry(); - } catch (error) { - remoteEntryExports = - (await host.remoteHandler.hooks.lifecycle.errorLoadRemote.emit({ - id: key, - error, - from: 'runtime', - lifecycle: 'beforeLoadShare', - origin: host, - })) as RemoteEntryExports; - } - if (!module.inited) { - await initFn(remoteEntryExports); - module.inited = true; - } - } + await module.init(); }; Object.keys(host.options.shared).forEach((shareName) => { const sharedArr = host.options.shared[shareName]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8dba5279e94..0e3eada9e5b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -193,7 +193,7 @@ importers: version: 11.0.3(semantic-release@24.2.9) '@storybook/addon-docs': specifier: 9.0.17 - version: 9.0.17(@types/react@18.3.11)(storybook@9.0.9) + version: 9.0.17(@types/react@19.2.2)(storybook@9.0.9) '@storybook/nextjs': specifier: 9.0.9 version: 9.0.9(@rspack/core@1.3.9)(@swc/core@1.7.26)(esbuild@0.25.0)(next@14.2.16)(react-dom@18.3.1)(react@18.3.1)(storybook@9.0.9)(typescript@5.8.3)(webpack-cli@5.1.4)(webpack@5.98.0) @@ -220,7 +220,7 @@ importers: version: 0.5.9(tailwindcss@3.4.13) '@testing-library/react': specifier: 16.1.0 - version: 16.1.0(@testing-library/dom@10.4.1)(@types/react@18.3.11)(react-dom@18.3.1)(react@18.3.1) + version: 16.1.0(@testing-library/dom@10.4.1)(@types/react@19.2.2)(react-dom@18.3.1)(react@18.3.1) '@types/adm-zip': specifier: 0.5.5 version: 0.5.5 @@ -2860,37 +2860,40 @@ importers: packages/chrome-devtools: dependencies: + '@antv/g6': + specifier: 4.8.24 + version: 4.8.24 '@arco-design/web-react': - specifier: ^2.64.1 - version: 2.64.1(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) + specifier: 2.66.7 + version: 2.66.7(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) '@modern-js/runtime': specifier: 2.68.2 - version: 2.68.2(react-dom@18.3.1)(react@18.3.1) + version: 2.68.2(react-dom@19.2.0)(react@19.2.0) '@module-federation/sdk': specifier: workspace:* version: link:../sdk ahooks: specifier: ^3.7.10 - version: 3.8.1(react@18.3.1) + version: 3.8.1(react@19.2.0) dagre: specifier: ^0.8.5 version: 0.8.5 react: - specifier: ~18.3.1 - version: 18.3.1 + specifier: ^19.2.0 + version: 19.2.0 react-dom: - specifier: ~18.3.1 - version: 18.3.1(react@18.3.1) + specifier: ^19.2.0 + version: 19.2.0(react@19.2.0) reactflow: specifier: 11.11.4 - version: 11.11.4(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) + version: 11.11.4(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) devDependencies: '@modern-js-app/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@5.0.4) '@modern-js/app-tools': specifier: 2.68.2 - version: 2.68.2(@rspack/core@1.3.9)(@swc/core@1.7.26)(encoding@0.1.13)(react-dom@18.3.1)(react@18.3.1)(styled-components@6.1.8)(ts-node@10.9.1)(typescript@5.0.4)(webpack-cli@5.1.4) + version: 2.68.2(@rspack/core@1.3.9)(@swc/core@1.7.26)(encoding@0.1.13)(react-dom@19.2.0)(react@19.2.0)(styled-components@6.1.8)(ts-node@10.9.1)(typescript@5.0.4)(webpack-cli@5.1.4) '@modern-js/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@5.0.4) @@ -2899,7 +2902,7 @@ importers: version: 2.68.2(typescript@5.0.4) '@modern-js/storybook': specifier: 2.68.2 - version: 2.68.2(@rspack/core@1.3.9)(@types/react-dom@18.3.0)(@types/react@18.2.79)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1)(react@18.3.1)(styled-components@6.1.8)(typescript@5.0.4)(webpack-cli@5.1.4)(webpack@5.98.0) + version: 2.68.2(@rspack/core@1.3.9)(@types/react-dom@19.2.2)(@types/react@19.2.2)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@19.2.0)(react@19.2.0)(styled-components@6.1.8)(typescript@5.0.4)(webpack-cli@5.1.4)(webpack@5.98.0) '@modern-js/tsconfig': specifier: 2.68.2 version: 2.68.2 @@ -2922,11 +2925,11 @@ importers: specifier: ~20.12.12 version: 20.12.14 '@types/react': - specifier: ~18.2.0 - version: 18.2.79 + specifier: ^19.2.2 + version: 19.2.2 '@types/react-dom': - specifier: ~18.3.0 - version: 18.3.0 + specifier: ^19.2.2 + version: 19.2.2(@types/react@19.2.2) lint-staged: specifier: ~13.1.0 version: 13.1.4 @@ -3866,6 +3869,12 @@ packages: '@jridgewell/gen-mapping': 0.3.12 '@jridgewell/trace-mapping': 0.3.29 + /@ant-design/colors@4.0.5: + resolution: {integrity: sha512-3mnuX2prnWOWvpFTS2WH2LoouWlOgtnIpc6IarWN6GOzzLF8dW/U8UctuvIPhoboETehZfJ61XP+CGakBEPJ3Q==} + dependencies: + tinycolor2: 1.6.0 + dev: false + /@ant-design/colors@6.0.0: resolution: {integrity: sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==} dependencies: @@ -3999,14 +4008,254 @@ packages: throttle-debounce: 5.0.2 dev: false + /@antv/algorithm@0.1.26: + resolution: {integrity: sha512-DVhcFSQ8YQnMNW34Mk8BSsfc61iC1sAnmcfYoXTAshYHuU50p/6b7x3QYaGctDNKWGvi1ub7mPcSY0bK+aN0qg==} + dependencies: + '@antv/util': 2.0.17 + tslib: 2.8.1 + dev: false + + /@antv/dom-util@2.0.4: + resolution: {integrity: sha512-2shXUl504fKwt82T3GkuT4Uoc6p9qjCKnJ8gXGLSW4T1W37dqf9AV28aCfoVPHp2BUXpSsB+PAJX2rG/jLHsLQ==} + dependencies: + tslib: 2.8.1 + dev: false + + /@antv/event-emitter@0.1.3: + resolution: {integrity: sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg==} + dev: false + + /@antv/g-base@0.5.16: + resolution: {integrity: sha512-jP06wggTubDPHXoKwFg3/f1lyxBX9ywwN3E/HG74Nd7DXqOXQis8tsIWW+O6dS/h9vyuXLd1/wDWkMMm3ZzXdg==} + dependencies: + '@antv/event-emitter': 0.1.3 + '@antv/g-math': 0.1.9 + '@antv/matrix-util': 3.1.0-beta.3 + '@antv/path-util': 2.0.15 + '@antv/util': 2.0.17 + '@types/d3-timer': 2.0.3 + d3-ease: 1.0.7 + d3-interpolate: 3.0.1 + d3-timer: 1.0.10 + detect-browser: 5.3.0 + tslib: 2.8.1 + dev: false + + /@antv/g-canvas@0.5.17: + resolution: {integrity: sha512-sXYJMWTOlb/Ycb6sTKu00LcJqInXJY4t99+kSM40u2OfqrXYmaXDjHR7D2V0roMkbK/QWiWS9UnEidCR1VtMOA==} + dependencies: + '@antv/g-base': 0.5.16 + '@antv/g-math': 0.1.9 + '@antv/matrix-util': 3.1.0-beta.3 + '@antv/path-util': 2.0.15 + '@antv/util': 2.0.17 + gl-matrix: 3.4.4 + tslib: 2.8.1 + dev: false + + /@antv/g-math@0.1.9: + resolution: {integrity: sha512-KHMSfPfZ5XHM1PZnG42Q2gxXfOitYveNTA7L61lR6mhZ8Y/aExsYmHqaKBsSarU0z+6WLrl9C07PQJZaw0uljQ==} + dependencies: + '@antv/util': 2.0.17 + gl-matrix: 3.4.4 + dev: false + + /@antv/g-svg@0.5.7: + resolution: {integrity: sha512-jUbWoPgr4YNsOat2Y/rGAouNQYGpw4R0cvlN0YafwOyacFFYy2zC8RslNd6KkPhhR3XHNSqJOuCYZj/YmLUwYw==} + dependencies: + '@antv/g-base': 0.5.16 + '@antv/g-math': 0.1.9 + '@antv/util': 2.0.17 + detect-browser: 5.3.0 + tslib: 2.8.1 + dev: false + + /@antv/g-webgpu-core@0.7.2: + resolution: {integrity: sha512-xUMmop7f3Rs34zFYKXLqHhDR1CQTeDl/7vI7Sn3X/73BqJc3X3HIIRvm83Fg2CjVACaOzw4WeLRXNaOCp9fz9w==} + dependencies: + eventemitter3: 4.0.7 + gl-matrix: 3.4.4 + lodash: 4.17.21 + probe.gl: 3.6.0 + dev: false + + /@antv/g-webgpu-engine@0.7.2: + resolution: {integrity: sha512-lx8Y93IW2cnJvdoDRKyMmTdYqSC1pOmF0nyG3PGGyA0NI9vBYVgO0KTF6hkyWjdTWVq7XDZyf/h8CJridLh3lg==} + dependencies: + '@antv/g-webgpu-core': 0.7.2 + gl-matrix: 3.4.4 + lodash: 4.17.21 + regl: 1.7.0 + dev: false + + /@antv/g-webgpu@0.7.2: + resolution: {integrity: sha512-kw+oYGsdvj5qeUfy5DPb/jztZBV+2fmqBd3Vv8NlKatfBmv8AirYX/CCW74AUSdWm99rEiLyxFB1VdRZ6b/wnQ==} + dependencies: + '@antv/g-webgpu-core': 0.7.2 + '@antv/g-webgpu-engine': 0.7.2 + gl-matrix: 3.4.4 + gl-vec2: 1.3.0 + lodash: 4.17.21 + dev: false + + /@antv/g6-core@0.8.24: + resolution: {integrity: sha512-rgI3dArAD8uoSz2+skS4ctN4x/Of33ivTIKaEYYvClxgkLZWVz9zvocy+5AWcVPBHZsAXkZcdh9zndIoWY/33A==} + dependencies: + '@antv/algorithm': 0.1.26 + '@antv/dom-util': 2.0.4 + '@antv/event-emitter': 0.1.3 + '@antv/g-base': 0.5.16 + '@antv/g-math': 0.1.9 + '@antv/matrix-util': 3.1.0-beta.3 + '@antv/path-util': 2.0.15 + '@antv/util': 2.0.17 + ml-matrix: 6.12.1 + tslib: 2.8.1 + dev: false + + /@antv/g6-element@0.8.24(@antv/g6@4.8.24): + resolution: {integrity: sha512-61FXkt9LY+6EOUtSam1iFTOW2AM59sPVcV1BuPj4dXiD0dluLE+R7d8B/94g1tKDw9tsjhfUQGC7hTXscJRJFw==} + peerDependencies: + '@antv/g6': 4.8.24 + dependencies: + '@antv/g-base': 0.5.16 + '@antv/g6': 4.8.24 + '@antv/g6-core': 0.8.24 + '@antv/util': 2.0.17 + tslib: 2.8.1 + dev: false + + /@antv/g6-pc@0.8.24(@antv/g6@4.8.24): + resolution: {integrity: sha512-nf0y1lrp8J5DotqRryXd2S/J30COW8spVcLF9gUqywGqQAHfE00Ywkqr+PZBnsfCZXsXCi9o0+CE9NrkWs4SBQ==} + dependencies: + '@ant-design/colors': 4.0.5 + '@antv/algorithm': 0.1.26 + '@antv/dom-util': 2.0.4 + '@antv/event-emitter': 0.1.3 + '@antv/g-base': 0.5.16 + '@antv/g-canvas': 0.5.17 + '@antv/g-math': 0.1.9 + '@antv/g-svg': 0.5.7 + '@antv/g6-core': 0.8.24 + '@antv/g6-element': 0.8.24(@antv/g6@4.8.24) + '@antv/g6-plugin': 0.8.24(@antv/g6@4.8.24) + '@antv/hierarchy': 0.6.14 + '@antv/layout': 0.3.25(dagre@0.8.5) + '@antv/matrix-util': 3.1.0-beta.3 + '@antv/path-util': 2.0.15 + '@antv/util': 2.0.17 + color: 3.2.1 + d3-force: 2.1.1 + dagre: 0.8.5 + insert-css: 2.0.0 + ml-matrix: 6.12.1 + tslib: 2.8.1 + transitivePeerDependencies: + - '@antv/g6' + dev: false + + /@antv/g6-plugin@0.8.24(@antv/g6@4.8.24): + resolution: {integrity: sha512-ZIOnwLTC7SM2bFiJZ3vYFWnkyOCWKqnU96i/fBh1qAoY5slDS3hatenZWEXUtOcqaKw1h+5A5f72MRXqBBVn0g==} + peerDependencies: + '@antv/g6': 4.8.24 + dependencies: + '@antv/dom-util': 2.0.4 + '@antv/g-base': 0.5.16 + '@antv/g-canvas': 0.5.17 + '@antv/g-svg': 0.5.7 + '@antv/g6': 4.8.24 + '@antv/g6-core': 0.8.24 + '@antv/g6-element': 0.8.24(@antv/g6@4.8.24) + '@antv/matrix-util': 3.1.0-beta.3 + '@antv/path-util': 2.0.15 + '@antv/scale': 0.3.18 + '@antv/util': 2.0.17 + insert-css: 2.0.0 + dev: false + + /@antv/g6@4.8.24: + resolution: {integrity: sha512-bgj7sZ+z45JmOngIpYpwmSIg7SboMLZBoAlX0+RoAETZB3/xvZO0MXT3lCSyAhIgm5Sb68pekKi7OStuo04NyQ==} + dependencies: + '@antv/g6-pc': 0.8.24(@antv/g6@4.8.24) + dev: false + + /@antv/graphlib@1.2.0: + resolution: {integrity: sha512-hhJOMThec51nU4Fe5p/viLlNIL71uDEgYFzKPajWjr2715SFG1HAgiP6AVylIeqBcAZ04u3Lw7usjl/TuI5RuQ==} + dev: false + + /@antv/hierarchy@0.6.14: + resolution: {integrity: sha512-V3uknf7bhynOqQDw2sg+9r9DwZ9pc6k/EcqyTFdfXB1+ydr7urisP0MipIuimucvQKN+Qkd+d6w601r1UIroqQ==} + dev: false + + /@antv/layout@0.3.25(dagre@0.8.5): + resolution: {integrity: sha512-d29Aw1PXoAavMRZy7iTB9L5rMBeChFEX0BJ9ELP4TI35ySdCu07YbmPo9ju9OH/6sG2/NB3o85Ayxrre3iwX/g==} + dependencies: + '@antv/g-webgpu': 0.7.2 + '@antv/graphlib': 1.2.0 + '@antv/util': 3.3.11 + d3-force: 2.1.1 + d3-quadtree: 2.0.0 + dagre-compound: 0.0.11(dagre@0.8.5) + ml-matrix: 6.5.0 + transitivePeerDependencies: + - dagre + dev: false + + /@antv/matrix-util@3.0.4: + resolution: {integrity: sha512-BAPyu6dUliHcQ7fm9hZSGKqkwcjEDVLVAstlHULLvcMZvANHeLXgHEgV7JqcAV/GIhIz8aZChIlzM1ZboiXpYQ==} + dependencies: + '@antv/util': 2.0.17 + gl-matrix: 3.4.4 + tslib: 2.8.1 + dev: false + + /@antv/matrix-util@3.1.0-beta.3: + resolution: {integrity: sha512-W2R6Za3A6CmG51Y/4jZUM/tFgYSq7vTqJL1VD9dKrvwxS4sE0ZcXINtkp55CdyBwJ6Cwm8pfoRpnD4FnHahN0A==} + dependencies: + '@antv/util': 2.0.17 + gl-matrix: 3.4.4 + tslib: 2.8.1 + dev: false + + /@antv/path-util@2.0.15: + resolution: {integrity: sha512-R2VLZ5C8PLPtr3VciNyxtjKqJ0XlANzpFb5sE9GE61UQqSRuSVSzIakMxjEPrpqbgc+s+y8i+fmc89Snu7qbNw==} + dependencies: + '@antv/matrix-util': 3.0.4 + '@antv/util': 2.0.17 + tslib: 2.8.1 + dev: false + + /@antv/scale@0.3.18: + resolution: {integrity: sha512-GHwE6Lo7S/Q5fgaLPaCsW+CH+3zl4aXpnN1skOiEY0Ue9/u+s2EySv6aDXYkAqs//i0uilMDD/0/4n8caX9U9w==} + dependencies: + '@antv/util': 2.0.17 + fecha: 4.2.3 + tslib: 2.8.1 + dev: false + + /@antv/util@2.0.17: + resolution: {integrity: sha512-o6I9hi5CIUvLGDhth0RxNSFDRwXeywmt6ExR4+RmVAzIi48ps6HUy+svxOCayvrPBN37uE6TAc2KDofRo0nK9Q==} + dependencies: + csstype: 3.1.3 + tslib: 2.8.1 + dev: false + + /@antv/util@3.3.11: + resolution: {integrity: sha512-FII08DFM4ABh2q5rPYdr0hMtKXRgeZazvXaFYCs7J7uTcWDHUhczab2qOCJLNDugoj8jFag1djb7wS9ehaRYBg==} + dependencies: + fast-deep-equal: 3.1.3 + gl-matrix: 3.4.4 + tslib: 2.8.1 + dev: false + /@arco-design/color@0.4.0: resolution: {integrity: sha512-s7p9MSwJgHeL8DwcATaXvWT3m2SigKpxx4JA1BGPHL4gfvaQsmQfrLBDpjOJFJuJ2jG2dMt3R3P8Pm9E65q18g==} dependencies: color: 3.2.1 dev: false - /@arco-design/web-react@2.64.1(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-fBD3m5vAywHA41DFiIHhVpRJVuEb27rXcn8kKcVC4OHN20NLCqJ8keLfyghSvy7A3+RVUSEsOtJMlpDB8PzHGw==} + /@arco-design/web-react@2.66.7(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): + resolution: {integrity: sha512-heZoNjsdD2tXFAv0SmVsMsMFVcwhOVUsjqfRZZtW7WHAWIx1vygbVJceww61DgBwFXPtYPUlyu2SRmPiVz2xlg==} peerDependencies: react: '>=16' react-dom: '>=16' @@ -4019,11 +4268,11 @@ packages: dayjs: 1.11.13 lodash: 4.17.21 number-precision: 1.6.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-focus-lock: 2.13.2(@types/react@18.2.79)(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-focus-lock: 2.13.2(@types/react@19.2.2)(react@19.2.0) react-is: 18.3.1 - react-transition-group: 4.4.5(react-dom@18.3.1)(react@18.3.1) + react-transition-group: 4.4.5(react-dom@19.2.0)(react@19.2.0) resize-observer-polyfill: 1.5.1 scroll-into-view-if-needed: 2.2.31 shallowequal: 1.1.0 @@ -7144,11 +7393,11 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.0 + '@babel/generator': 7.28.3 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.0 + '@babel/parser': 7.28.4 '@babel/template': 7.27.2 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -7158,11 +7407,11 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.0 + '@babel/generator': 7.28.3 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.0 + '@babel/parser': 7.28.4 '@babel/template': 7.27.2 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -8280,6 +8529,7 @@ packages: react: '>=16.8.0' dependencies: react: 18.3.1 + dev: false /@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@19.0.0): resolution: {integrity: sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==} @@ -8289,6 +8539,14 @@ packages: react: 19.0.0 dev: false + /@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@19.2.0): + resolution: {integrity: sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==} + peerDependencies: + react: '>=16.8.0' + dependencies: + react: 19.2.0 + dev: true + /@emotion/utils@1.4.1: resolution: {integrity: sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==} dev: false @@ -9810,15 +10068,15 @@ packages: '@floating-ui/utils': 0.2.8 dev: true - /@floating-ui/react-dom@2.1.2(react-dom@18.3.1)(react@18.3.1): + /@floating-ui/react-dom@2.1.2(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' dependencies: '@floating-ui/dom': 1.6.11 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true /@floating-ui/utils@0.2.8: @@ -10520,6 +10778,17 @@ packages: react: 18.3.1 react-is: 16.13.1 + /@loadable/component@5.15.3(react@19.2.0): + resolution: {integrity: sha512-VOgYgCABn6+/7aGIpg7m0Ruj34tGetaJzt4bQ345FwEovDQZ+dua+NWLmuJKv8rWZyxOUSfoJkmGnzyDXH2BAQ==} + engines: {node: '>=8'} + peerDependencies: + react: ^16.3.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@babel/runtime': 7.28.2 + hoist-non-react-statics: 3.3.2 + react: 19.2.0 + react-is: 16.13.1 + /@loadable/server@5.15.3(@loadable/component@5.15.3)(react@18.3.1): resolution: {integrity: sha512-Bm/BGe+RlChuHDKNNXpQOi4AJ0cKVuSLI+J8U0Q06zTIfT0S1RLoy85qs5RXm3cLIfefygL8+9bcYFgeWcoM8A==} engines: {node: '>=8'} @@ -10531,6 +10800,17 @@ packages: lodash: 4.17.21 react: 18.3.1 + /@loadable/server@5.15.3(@loadable/component@5.15.3)(react@19.2.0): + resolution: {integrity: sha512-Bm/BGe+RlChuHDKNNXpQOi4AJ0cKVuSLI+J8U0Q06zTIfT0S1RLoy85qs5RXm3cLIfefygL8+9bcYFgeWcoM8A==} + engines: {node: '>=8'} + peerDependencies: + '@loadable/component': ^5.0.1 + react: ^16.3.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@loadable/component': 5.15.3(react@19.2.0) + lodash: 4.17.21 + react: 19.2.0 + /@manypkg/find-root@1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} dependencies: @@ -10672,22 +10952,22 @@ packages: - supports-color dev: false - /@mdx-js/react@1.6.22(react@18.3.1): + /@mdx-js/react@1.6.22(react@19.2.0): resolution: {integrity: sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==} peerDependencies: react: ^16.13.1 || ^17.0.0 dependencies: - react: 18.3.1 + react: 19.2.0 dev: true - /@mdx-js/react@2.3.0(react@19.1.1): + /@mdx-js/react@2.3.0(react@19.2.0): resolution: {integrity: sha512-zQH//gdOmuu7nt2oJR29vFhDv88oGPmVw6BggmrHeMI+xgEkp1B2dX9/bMBSYtK0dyLX/aOmesKS09g222K1/g==} peerDependencies: react: '>=16' dependencies: '@types/mdx': 2.0.13 - '@types/react': 18.3.11 - react: 19.1.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: false /@mdx-js/react@3.1.0(@types/react@18.3.11)(react@18.3.1): @@ -10701,7 +10981,7 @@ packages: react: 18.3.1 dev: true - /@mdx-js/react@3.1.0(@types/react@19.1.8)(react@19.1.1): + /@mdx-js/react@3.1.0(@types/react@19.1.8)(react@19.2.0): resolution: {integrity: sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==} peerDependencies: '@types/react': '>=16' @@ -10709,9 +10989,20 @@ packages: dependencies: '@types/mdx': 2.0.13 '@types/react': 19.1.8 - react: 19.1.1 + react: 19.2.0 dev: false + /@mdx-js/react@3.1.0(@types/react@19.2.2)(react@18.3.1): + resolution: {integrity: sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==} + peerDependencies: + '@types/react': '>=16' + react: '>=16' + dependencies: + '@types/mdx': 2.0.13 + '@types/react': 19.2.2 + react: 18.3.1 + dev: true + /@mdx-js/react@3.1.1(@types/react@18.3.11)(react@18.3.1): resolution: {integrity: sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==} peerDependencies: @@ -10723,7 +11014,7 @@ packages: react: 18.3.1 dev: true - /@mdx-js/react@3.1.1(@types/react@19.1.8)(react@19.1.1): + /@mdx-js/react@3.1.1(@types/react@19.1.8)(react@19.2.0): resolution: {integrity: sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==} peerDependencies: '@types/react': '>=16' @@ -10731,7 +11022,7 @@ packages: dependencies: '@types/mdx': 2.0.13 '@types/react': 19.1.8 - react: 19.1.1 + react: 19.2.0 dev: false /@mdx-js/util@1.6.22: @@ -10928,7 +11219,7 @@ packages: immer: 9.0.21 dev: true - /@modern-js-reduck/react@1.1.11(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@modern-js-reduck/react@1.1.11(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-6ViI1wyrkSIAkwpKfK6bC8dnzmyfp2FTWL2AAI2PrIYNAhd+jMuTM4ik6xDHncQmTny3+rAH2B8FfsUIVm7fxQ==} peerDependencies: '@types/react': ^16.8 || ^17.0 || ^18.0 @@ -10947,12 +11238,12 @@ packages: '@modern-js-reduck/plugin-immutable': 1.1.11(@modern-js-reduck/store@1.1.11) '@modern-js-reduck/store': 1.1.11 '@swc/helpers': 0.5.1 - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) hoist-non-react-statics: 3.3.2 invariant: 2.2.4 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true /@modern-js-reduck/store@1.1.11: @@ -11172,6 +11463,76 @@ packages: - webpack-plugin-serve dev: true + /@modern-js/app-tools@2.68.2(@rspack/core@1.3.9)(@swc/core@1.7.26)(encoding@0.1.13)(react-dom@19.2.0)(react@19.2.0)(styled-components@6.1.8)(ts-node@10.9.1)(typescript@5.0.4)(webpack-cli@5.1.4): + resolution: {integrity: sha512-fOhDC+WzYUtEZrPd35eOr1NEwybu+QCKMqhk8YsRG+DBUYrglVCub6VSHAu+fqOA1bXIyZbS+dYrCq8t3PebRA==} + engines: {node: '>=14.17.6'} + hasBin: true + peerDependencies: + ts-node: ^10.7.0 + tsconfig-paths: ^4.2.0 + peerDependenciesMeta: + ts-node: + optional: true + tsconfig-paths: + optional: true + dependencies: + '@babel/parser': 7.27.2 + '@babel/traverse': 7.27.1 + '@babel/types': 7.28.2 + '@modern-js/core': 2.68.2 + '@modern-js/node-bundle-require': 2.68.2 + '@modern-js/plugin': 2.68.2 + '@modern-js/plugin-data-loader': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/plugin-i18n': 2.68.2 + '@modern-js/plugin-v2': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/prod-server': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/rsbuild-plugin-esbuild': 2.68.2(@swc/core@1.7.26)(webpack-cli@5.1.4) + '@modern-js/server': 2.68.2(@babel/traverse@7.27.1)(@rsbuild/core@1.4.4)(react-dom@19.2.0)(react@19.2.0)(ts-node@10.9.1) + '@modern-js/server-core': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/server-utils': 2.68.2(@babel/traverse@7.27.1)(@rsbuild/core@1.4.4) + '@modern-js/types': 2.68.2 + '@modern-js/uni-builder': 2.68.2(@rspack/core@1.3.9)(esbuild@0.25.5)(styled-components@6.1.8)(typescript@5.0.4)(webpack-cli@5.1.4) + '@modern-js/utils': 2.68.2 + '@rsbuild/core': 1.4.4 + '@rsbuild/plugin-node-polyfill': 1.3.0(@rsbuild/core@1.4.4) + '@swc/helpers': 0.5.17 + es-module-lexer: 1.6.0 + esbuild: 0.25.5 + esbuild-register: 3.6.0(esbuild@0.25.5) + flatted: 3.3.3 + mlly: 1.7.4 + ndepe: 0.1.12(encoding@0.1.13) + pkg-types: 1.3.1 + std-env: 3.7.0 + ts-node: 10.9.1(@swc/core@1.7.26)(@types/node@18.16.9)(typescript@5.8.3) + transitivePeerDependencies: + - '@parcel/css' + - '@rspack/core' + - '@swc/core' + - '@swc/css' + - '@types/webpack' + - bufferutil + - clean-css + - csso + - debug + - devcert + - encoding + - lightningcss + - react + - react-dom + - sockjs-client + - styled-components + - supports-color + - type-fest + - typescript + - uglify-js + - utf-8-validate + - webpack-cli + - webpack-dev-server + - webpack-hot-middleware + - webpack-plugin-serve + dev: true + /@modern-js/babel-compiler@2.68.0: resolution: {integrity: sha512-R5zl+9rInHMaesxUjEyV3b/4p/KAboEHpi+PTJrL7no+rvxWdLIG5oPDUuGwOBsIpGaeVR19Zai/nPpkpc4hbA==} dependencies: @@ -11472,6 +11833,22 @@ packages: - react-dom - supports-color + /@modern-js/plugin-data-loader@2.68.2(react-dom@19.2.0)(react@19.2.0): + resolution: {integrity: sha512-kjdpkpQCZJBQ8/PVxgiQPzd36aYULhfdWilxzM7muIGNBgIxVbON9hRNK/ATIGEDGOHIIOT/rdYxHUTty19g7g==} + engines: {node: '>=16.2.0'} + peerDependencies: + react: '>=17.0.0' + dependencies: + '@babel/core': 7.28.0 + '@modern-js/runtime-utils': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/utils': 2.68.2 + '@swc/helpers': 0.5.17 + path-to-regexp: 6.3.0 + react: 19.2.0 + transitivePeerDependencies: + - react-dom + - supports-color + /@modern-js/plugin-i18n@2.68.0: resolution: {integrity: sha512-lTssQ8ln4+qqNyW/tb7MJVuFVT8kmhqg7q/UZMmKKV0aqKzR5o7VoMfK01V2l9Q8V7n5ZWjQgAOYbXOuBjiCxg==} dependencies: @@ -11486,7 +11863,7 @@ packages: '@swc/helpers': 0.5.17 dev: true - /@modern-js/plugin-state@2.68.2(@modern-js/runtime@2.68.2)(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@modern-js/plugin-state@2.68.2(@modern-js/runtime@2.68.2)(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-MiSYo7EQQ14XlgHeeeVcOM7qVGTasfs7AJgbp+aPE/AnZV0ju9346v7z6mOL6LDIx7pzvOeYs0dbCEPw5qW6ug==} peerDependencies: '@modern-js/runtime': ^2.68.2 @@ -11497,15 +11874,15 @@ packages: '@modern-js-reduck/plugin-devtools': 1.1.11(@modern-js-reduck/store@1.1.11) '@modern-js-reduck/plugin-effects': 1.1.11(@modern-js-reduck/store@1.1.11) '@modern-js-reduck/plugin-immutable': 1.1.11(@modern-js-reduck/store@1.1.11) - '@modern-js-reduck/react': 1.1.11(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) + '@modern-js-reduck/react': 1.1.11(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) '@modern-js-reduck/store': 1.1.11 - '@modern-js/runtime': 2.68.2(react-dom@18.3.1)(react@18.3.1) - '@modern-js/runtime-utils': 2.68.2(react-dom@18.3.1)(react@18.3.1) + '@modern-js/runtime': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/runtime-utils': 2.68.2(react-dom@19.2.0)(react@19.2.0) '@modern-js/types': 2.68.2 '@modern-js/utils': 2.68.2 '@swc/helpers': 0.5.17 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -11537,6 +11914,19 @@ packages: - react - react-dom + /@modern-js/plugin-v2@2.68.2(react-dom@19.2.0)(react@19.2.0): + resolution: {integrity: sha512-FWwC3RC6Vt/CkXGNP3SQp7S1lhd5r50kSby20usBF+oITxmm1NohETC3ojiJ3jp6JAmVqDvZvRkC0R8eW55vQg==} + dependencies: + '@modern-js/runtime-utils': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/types': 2.68.2 + '@modern-js/utils': 2.68.2 + '@rsbuild/core': 1.4.4 + '@swc/helpers': 0.5.17 + jiti: 1.21.7 + transitivePeerDependencies: + - react + - react-dom + /@modern-js/plugin@2.68.0: resolution: {integrity: sha512-Pz0m0mKL57Ws91spmUvQirwfh2izUHRvlY+KZ42C5P68cyh9bXmmYecKeytpFp2bxiAbmZ+JZIAILh9vIqejQw==} dependencies: @@ -11575,6 +11965,19 @@ packages: - react-dom dev: true + /@modern-js/prod-server@2.68.2(react-dom@19.2.0)(react@19.2.0): + resolution: {integrity: sha512-+jY4crGFKgFSC3g+haLyh/qSrBNRADzOLlcrTCH/APkKOsEZO46uSofLI6kFI3fBLJioyU0SiRfYLp03K39BNQ==} + engines: {node: '>=16.2.0'} + dependencies: + '@modern-js/runtime-utils': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/server-core': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/utils': 2.68.2 + '@swc/helpers': 0.5.17 + transitivePeerDependencies: + - react + - react-dom + dev: true + /@modern-js/render@2.68.0(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-tWO6d4d9A1F89zkHgDtgc2Wl1S9q6UPhUn57yt4PuWjs4VdI3KSYyOg618y1cV1smdrdw77MyZtxRo5LdFT1dA==} peerDependencies: @@ -11601,6 +12004,18 @@ packages: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + /@modern-js/render@2.68.2(react-dom@19.2.0)(react@19.2.0): + resolution: {integrity: sha512-cNW2PNmHeOmVfIIjE2XDSTnb/WnYJZMRqvm0ABpzjAQE5dpCIRongzIrtX/Ls4RFFulj9ZFijAYoZkJ2Ui9Yuw==} + peerDependencies: + react: '>=17.0.0' + react-dom: '>=17.0.0' + dependencies: + '@modern-js/types': 2.68.2 + '@modern-js/utils': 2.68.2 + '@swc/helpers': 0.5.17 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + /@modern-js/rsbuild-plugin-esbuild@2.68.0(@swc/core@1.7.26)(webpack-cli@5.1.4): resolution: {integrity: sha512-6vSaHEV7Kd9zH5+UqD28A9RvWnymCy38WF1mvYOVJoRBSjzMjrIaF5vyGmnHlTlJhxgVPhFEO0jAQxnV/F/PMA==} dependencies: @@ -11667,6 +12082,27 @@ packages: react-router-dom: 6.27.0(react-dom@18.3.1)(react@18.3.1) serialize-javascript: 6.0.2 + /@modern-js/runtime-utils@2.68.2(react-dom@19.2.0)(react@19.2.0): + resolution: {integrity: sha512-IYUW5J3XvKfqUuDY3MSZ0Q8zTKZ2yW2XJttXXAHQSd9NQ9gamyRPI8ysR7jTy1bHjbRY6TB86t8kw2zvwW1E0A==} + peerDependencies: + react: '>=17.0.0' + react-dom: '>=17.0.0' + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + dependencies: + '@modern-js/types': 2.68.2 + '@modern-js/utils': 2.68.2 + '@remix-run/router': 1.20.0 + '@swc/helpers': 0.5.17 + lru-cache: 10.4.3 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-router-dom: 6.27.0(react-dom@19.2.0)(react@19.2.0) + serialize-javascript: 6.0.2 + /@modern-js/runtime@2.68.0(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-HpTrvgTatG68NlRItlabUViGV/Xo0eEbbd4t3mgcctJG9Yp+F1/iYNv1R6wCHL7wN+hhiWKk+iggEEGwD4Aeyw==} engines: {node: '>=14.17.6'} @@ -11742,6 +12178,43 @@ packages: transitivePeerDependencies: - supports-color + /@modern-js/runtime@2.68.2(react-dom@19.2.0)(react@19.2.0): + resolution: {integrity: sha512-W8hqc7J+4uZhd7pRRRljljxpPM4C1aV/InIqkbHPUaFadB7Kdkoaur3ftgsK1nnhODRv4zFs5AmwY3hJiE4Rbw==} + engines: {node: '>=14.17.6'} + peerDependencies: + react: '>=17' + react-dom: '>=17' + dependencies: + '@babel/core': 7.28.0 + '@babel/types': 7.28.2 + '@loadable/babel-plugin': 5.15.3(@babel/core@7.28.0) + '@loadable/component': 5.15.3(react@19.2.0) + '@loadable/server': 5.15.3(@loadable/component@5.15.3)(react@19.2.0) + '@modern-js/plugin': 2.68.2 + '@modern-js/plugin-data-loader': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/plugin-v2': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/render': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/runtime-utils': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/types': 2.68.2 + '@modern-js/utils': 2.68.2 + '@swc/helpers': 0.5.17 + '@types/loadable__component': 5.13.9 + '@types/react-helmet': 6.1.11 + '@types/styled-components': 5.1.34 + cookie: 0.7.2 + es-module-lexer: 1.6.0 + esbuild: 0.25.5 + invariant: 2.2.4 + isbot: 3.7.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-helmet: 6.1.0(react@19.2.0) + react-is: 18.3.1 + react-side-effect: 2.1.2(react@19.2.0) + styled-components: 5.3.11(@babel/core@7.28.0)(react-dom@19.2.0)(react-is@18.3.1)(react@19.2.0) + transitivePeerDependencies: + - supports-color + /@modern-js/server-core@2.68.0(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-Wf9qg54gzMeUvM0As2zYoi9eb4oEhy2IJeq/J+f86YDVgpTI5hpDCV+uzZUQKs5o4OB7OppdeYY6qMzDL2OjVg==} engines: {node: '>=16.2.0'} @@ -11784,6 +12257,27 @@ packages: - react-dom dev: true + /@modern-js/server-core@2.68.2(react-dom@19.2.0)(react@19.2.0): + resolution: {integrity: sha512-K7pqbHgbRfyX7M7jr+Gp2/5p2ovySz1w8nmtqORnE7PXbkXZ4zglxrKqq+3x7BIjZNcSJ0ZpELv7L8w6BavG3g==} + engines: {node: '>=16.2.0'} + dependencies: + '@modern-js/plugin': 2.68.2 + '@modern-js/plugin-v2': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/runtime-utils': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/utils': 2.68.2 + '@swc/helpers': 0.5.17 + '@web-std/fetch': 4.2.1 + '@web-std/file': 3.0.3 + '@web-std/stream': 1.0.3 + cloneable-readable: 3.0.0 + flatted: 3.3.3 + hono: 3.12.12 + ts-deepmerge: 7.0.2 + transitivePeerDependencies: + - react + - react-dom + dev: true + /@modern-js/server-runtime@2.68.2(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-ZsD2tpMaA+ZCDlj9dDQAeLEzWxNGaPCaRENXbjIWLAL135tCD5wFUxmGtsAv/wvTMZcuCEwrsv8tbHPA6eb4bA==} dependencies: @@ -11915,27 +12409,67 @@ packages: - utf-8-validate dev: true - /@modern-js/storybook-builder@2.68.2(@rspack/core@1.3.9)(@types/react-dom@18.3.0)(@types/react@18.2.79)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1)(react@18.3.1)(styled-components@6.1.8)(typescript@5.0.4)(webpack-cli@5.1.4)(webpack@5.98.0): + /@modern-js/server@2.68.2(@babel/traverse@7.27.1)(@rsbuild/core@1.4.4)(react-dom@19.2.0)(react@19.2.0)(ts-node@10.9.1): + resolution: {integrity: sha512-O2KtXjev6RBeZ8C3KIgAIo+k2HBWBTgIWss5z3Z0bh+IijnaqaliYOBpG4sbrsLZwVu0c2CoNguG/v246pXDRA==} + peerDependencies: + devcert: ^1.2.2 + ts-node: ^10.1.0 + tsconfig-paths: '>= 3.0.0 || >= 4.0.0' + peerDependenciesMeta: + devcert: + optional: true + ts-node: + optional: true + tsconfig-paths: + optional: true + dependencies: + '@babel/core': 7.28.0 + '@babel/register': 7.25.7(@babel/core@7.28.0) + '@modern-js/runtime-utils': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/server-core': 2.68.2(react-dom@19.2.0)(react@19.2.0) + '@modern-js/server-utils': 2.68.2(@babel/traverse@7.27.1)(@rsbuild/core@1.4.4) + '@modern-js/types': 2.68.2 + '@modern-js/utils': 2.68.2 + '@swc/helpers': 0.5.17 + axios: 1.12.2 + connect-history-api-fallback: 2.0.0 + http-compression: 1.0.6 + minimatch: 3.1.2 + path-to-regexp: 6.3.0 + ts-node: 10.9.1(@swc/core@1.7.26)(@types/node@18.16.9)(typescript@5.8.3) + ws: 8.18.3 + transitivePeerDependencies: + - '@babel/traverse' + - '@rsbuild/core' + - bufferutil + - debug + - react + - react-dom + - supports-color + - utf-8-validate + dev: true + + /@modern-js/storybook-builder@2.68.2(@rspack/core@1.3.9)(@types/react-dom@19.2.2)(@types/react@19.2.2)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@19.2.0)(react@19.2.0)(styled-components@6.1.8)(typescript@5.0.4)(webpack-cli@5.1.4)(webpack@5.98.0): resolution: {integrity: sha512-yb5/aRgLBtPXYGULBCM+JILIwqI25LxzDFqU5vqg8XjU4t3ivimnJx1Fb+RMFtWaahcoqqoajKy5vPGw2zdN4g==} engines: {node: '>=16.0.0'} dependencies: '@modern-js/core': 2.68.2 - '@modern-js/plugin-state': 2.68.2(@modern-js/runtime@2.68.2)(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@modern-js/runtime': 2.68.2(react-dom@18.3.1)(react@18.3.1) + '@modern-js/plugin-state': 2.68.2(@modern-js/runtime@2.68.2)(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@modern-js/runtime': 2.68.2(react-dom@19.2.0)(react@19.2.0) '@modern-js/uni-builder': 2.68.2(@rspack/core@1.3.9)(esbuild@0.18.20)(styled-components@6.1.8)(typescript@5.0.4)(webpack-cli@5.1.4) '@modern-js/utils': 2.68.2 '@rsbuild/core': 1.4.4 - '@storybook/components': 7.6.20(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) + '@storybook/components': 7.6.20(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) '@storybook/core-common': 7.6.20(encoding@0.1.13) '@storybook/csf-plugin': 7.6.20 '@storybook/global': 5.0.0 - '@storybook/mdx1-csf': 1.0.0(react@18.3.1) + '@storybook/mdx1-csf': 1.0.0(react@19.2.0) '@storybook/mdx2-csf': 1.1.0 '@storybook/preview': 7.6.20 '@storybook/preview-api': 7.6.20 '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.0.4)(webpack@5.98.0) '@storybook/router': 7.6.20 - '@storybook/theming': 7.6.20(react-dom@18.3.1)(react@18.3.1) + '@storybook/theming': 7.6.20(react-dom@19.2.0)(react@19.2.0) ast-types: 0.14.2 minimatch: 9.0.5 react-docgen: 6.0.0-alpha.3 @@ -11970,14 +12504,14 @@ packages: - webpack-plugin-serve dev: true - /@modern-js/storybook@2.68.2(@rspack/core@1.3.9)(@types/react-dom@18.3.0)(@types/react@18.2.79)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1)(react@18.3.1)(styled-components@6.1.8)(typescript@5.0.4)(webpack-cli@5.1.4)(webpack@5.98.0): + /@modern-js/storybook@2.68.2(@rspack/core@1.3.9)(@types/react-dom@19.2.2)(@types/react@19.2.2)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@19.2.0)(react@19.2.0)(styled-components@6.1.8)(typescript@5.0.4)(webpack-cli@5.1.4)(webpack@5.98.0): resolution: {integrity: sha512-gMYbuEEt5l7e9VXYyh/AZ8y5E4ALmizyOIWyacGJ3dXBqC0OJq+UY3rm2EVCIl1sMvvL11AJ7OVzXWhiXHp5YQ==} engines: {node: '>=16.0.0'} hasBin: true dependencies: - '@modern-js/storybook-builder': 2.68.2(@rspack/core@1.3.9)(@types/react-dom@18.3.0)(@types/react@18.2.79)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1)(react@18.3.1)(styled-components@6.1.8)(typescript@5.0.4)(webpack-cli@5.1.4)(webpack@5.98.0) + '@modern-js/storybook-builder': 2.68.2(@rspack/core@1.3.9)(@types/react-dom@19.2.2)(@types/react@19.2.2)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@19.2.0)(react@19.2.0)(styled-components@6.1.8)(typescript@5.0.4)(webpack-cli@5.1.4)(webpack@5.98.0) '@modern-js/utils': 2.68.2 - '@storybook/react': 7.6.20(encoding@0.1.13)(react-dom@18.3.1)(react@18.3.1)(typescript@5.0.4) + '@storybook/react': 7.6.20(encoding@0.1.13)(react-dom@19.2.0)(react@19.2.0)(typescript@5.0.4) storybook: 7.6.20(encoding@0.1.13) transitivePeerDependencies: - '@parcel/css' @@ -15704,6 +16238,25 @@ packages: - supports-color dev: true + /@probe.gl/env@3.6.0: + resolution: {integrity: sha512-4tTZYUg/8BICC3Yyb9rOeoKeijKbZHRXBEKObrfPmX4sQmYB15ZOUpoVBhAyJkOYVAM8EkPci6Uw5dLCwx2BEQ==} + dependencies: + '@babel/runtime': 7.28.2 + dev: false + + /@probe.gl/log@3.6.0: + resolution: {integrity: sha512-hjpyenpEvOdowgZ1qMeCJxfRD4JkKdlXz0RC14m42Un62NtOT+GpWyKA4LssT0+xyLULCByRAtG2fzZorpIAcA==} + dependencies: + '@babel/runtime': 7.28.2 + '@probe.gl/env': 3.6.0 + dev: false + + /@probe.gl/stats@3.6.0: + resolution: {integrity: sha512-JdALQXB44OP4kUBN/UrQgzbJe4qokbVF4Y8lkIA8iVCFnjVowWIgkD/z/0QO65yELT54tTrtepw1jScjKB+rhQ==} + dependencies: + '@babel/runtime': 7.28.2 + dev: false + /@publint/pack@0.1.2: resolution: {integrity: sha512-S+9ANAvUmjutrshV4jZjaiG8XQyuJIZ8a4utWmN/vW1sgQ9IfBnPndwkmQYw53QmouOIytT874u65HEmu6H5jw==} engines: {node: '>=18'} @@ -15725,7 +16278,7 @@ packages: resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} dev: true - /@radix-ui/react-arrow@1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-arrow@1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} peerDependencies: '@types/react': '*' @@ -15739,14 +16292,14 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true - /@radix-ui/react-collection@1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-collection@1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} peerDependencies: '@types/react': '*' @@ -15760,17 +16313,17 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true - /@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-collection@1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==} peerDependencies: '@types/react': '*' @@ -15783,17 +16336,17 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-slot': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true - /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-compose-refs@1.0.1(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: '@types/react': '*' @@ -15803,11 +16356,11 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-compose-refs@1.1.0(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-compose-refs@1.1.0(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} peerDependencies: '@types/react': '*' @@ -15816,11 +16369,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-context@1.0.1(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-context@1.0.1(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} peerDependencies: '@types/react': '*' @@ -15830,11 +16383,11 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-context@1.1.0(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-context@1.1.0(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==} peerDependencies: '@types/react': '*' @@ -15843,11 +16396,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-direction@1.0.1(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-direction@1.0.1(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} peerDependencies: '@types/react': '*' @@ -15857,11 +16410,11 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-direction@1.1.0(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-direction@1.1.0(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} peerDependencies: '@types/react': '*' @@ -15870,11 +16423,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==} peerDependencies: '@types/react': '*' @@ -15889,17 +16442,17 @@ packages: dependencies: '@babel/runtime': 7.28.2 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true - /@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-focus-guards@1.0.1(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} peerDependencies: '@types/react': '*' @@ -15909,11 +16462,11 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-focus-scope@1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-focus-scope@1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ==} peerDependencies: '@types/react': '*' @@ -15927,16 +16480,16 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true - /@radix-ui/react-id@1.0.1(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-id@1.0.1(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} peerDependencies: '@types/react': '*' @@ -15946,12 +16499,12 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - react: 18.3.1 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-id@1.1.0(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-id@1.1.0(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} peerDependencies: '@types/react': '*' @@ -15960,12 +16513,12 @@ packages: '@types/react': optional: true dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - react: 18.3.1 + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-popper@1.1.2(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-popper@1.1.2(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==} peerDependencies: '@types/react': '*' @@ -15979,23 +16532,23 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.79)(react@18.3.1) + '@floating-ui/react-dom': 2.1.2(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-arrow': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-rect': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-size': 1.0.1(@types/react@19.2.2)(react@19.2.0) '@radix-ui/rect': 1.0.1 - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true - /@radix-ui/react-portal@1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-portal@1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA==} peerDependencies: '@types/react': '*' @@ -16009,14 +16562,14 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true - /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-primitive@1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: '@types/react': '*' @@ -16030,14 +16583,14 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true - /@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-primitive@2.0.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==} peerDependencies: '@types/react': '*' @@ -16050,14 +16603,14 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-slot': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true - /@radix-ui/react-roving-focus@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-roving-focus@1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==} peerDependencies: '@types/react': '*' @@ -16071,21 +16624,21 @@ packages: optional: true dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-direction': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-id': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: true - - /@radix-ui/react-select@1.2.2(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + '@radix-ui/react-collection': 1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + dev: true + + /@radix-ui/react-select@1.2.2(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==} peerDependencies: '@types/react': '*' @@ -16101,32 +16654,32 @@ packages: '@babel/runtime': 7.28.2 '@radix-ui/number': 1.0.1 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-id': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-popper': 1.1.2(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-portal': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.0.4(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-popper': 1.1.2(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-portal': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-use-previous': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) aria-hidden: 1.2.4 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.5.5(@types/react@18.2.79)(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.5.5(@types/react@19.2.2)(react@19.2.0) dev: true - /@radix-ui/react-separator@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-separator@1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==} peerDependencies: '@types/react': '*' @@ -16139,14 +16692,14 @@ packages: '@types/react-dom': optional: true dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true - /@radix-ui/react-slot@1.0.2(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-slot@1.0.2(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: '@types/react': '*' @@ -16156,12 +16709,12 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - react: 18.3.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-slot@1.1.0(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-slot@1.1.0(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} peerDependencies: '@types/react': '*' @@ -16170,12 +16723,12 @@ packages: '@types/react': optional: true dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - react: 18.3.1 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-toggle-group@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-toggle-group@1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-PpTJV68dZU2oqqgq75Uzto5o/XfOVgkrJ9rulVmfTKxWp3HfUjHE6CP/WLRR4AzPX9HWxw7vFow2me85Yu+Naw==} peerDependencies: '@types/react': '*' @@ -16189,19 +16742,19 @@ packages: optional: true dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-context': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-direction': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-toggle': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: true - - /@radix-ui/react-toggle@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + '@radix-ui/react-context': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-toggle': 1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + dev: true + + /@radix-ui/react-toggle@1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-gwoxaKZ0oJ4vIgzsfESBuSgJNdc0rv12VhHgcqN0TEJmmZixXG/2XpsLK8kzNWYcnaoRIEEQc0bEi3dIvdUpjw==} peerDependencies: '@types/react': '*' @@ -16215,15 +16768,15 @@ packages: optional: true dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true - /@radix-ui/react-toolbar@1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-toolbar@1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-ZUKknxhMTL/4hPh+4DuaTot9aO7UD6Kupj4gqXCsBTayX1pD1L+0C2/2VZKXb4tIifQklZ3pf2hG9T+ns+FclQ==} peerDependencies: '@types/react': '*' @@ -16237,19 +16790,19 @@ packages: optional: true dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-context': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-direction': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-separator': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-toggle-group': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: true - - /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.79)(react@18.3.1): + '@radix-ui/react-context': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-direction': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-separator': 1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-toggle-group': 1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + dev: true + + /@radix-ui/react-use-callback-ref@1.0.1(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} peerDependencies: '@types/react': '*' @@ -16259,11 +16812,11 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} peerDependencies: '@types/react': '*' @@ -16272,11 +16825,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-use-controllable-state@1.0.1(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} peerDependencies: '@types/react': '*' @@ -16286,12 +16839,12 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - react: 18.3.1 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} peerDependencies: '@types/react': '*' @@ -16300,12 +16853,12 @@ packages: '@types/react': optional: true dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - react: 18.3.1 + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} peerDependencies: '@types/react': '*' @@ -16315,12 +16868,12 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - react: 18.3.1 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-use-layout-effect@1.0.1(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} peerDependencies: '@types/react': '*' @@ -16330,11 +16883,11 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} peerDependencies: '@types/react': '*' @@ -16343,11 +16896,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-use-previous@1.0.1(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} peerDependencies: '@types/react': '*' @@ -16357,11 +16910,11 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-use-rect@1.0.1(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} peerDependencies: '@types/react': '*' @@ -16372,11 +16925,11 @@ packages: dependencies: '@babel/runtime': 7.28.2 '@radix-ui/rect': 1.0.1 - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-use-size@1.0.1(@types/react@18.2.79)(react@18.3.1): + /@radix-ui/react-use-size@1.0.1(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} peerDependencies: '@types/react': '*' @@ -16386,12 +16939,12 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.79)(react@18.3.1) - '@types/react': 18.2.79 - react: 18.3.1 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@19.2.2)(react@19.2.0) + '@types/react': 19.2.2 + react: 19.2.0 dev: true - /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} peerDependencies: '@types/react': '*' @@ -16405,11 +16958,11 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.2.79 - '@types/react-dom': 18.3.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@types/react': 19.2.2 + '@types/react-dom': 19.2.2(@types/react@19.2.2) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true /@radix-ui/rect@1.0.1: @@ -17171,39 +17724,39 @@ packages: react: 19.1.0 react-native: 0.80.0(@babel/core@7.28.0)(@react-native-community/cli@19.1.1)(@types/react@19.1.8)(react@19.1.0) - /@reactflow/background@11.3.14(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@reactflow/background@11.3.14(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-Gewd7blEVT5Lh6jqrvOgd4G6Qk17eGKQfsDXgyRSqM+CTwDqRldG2LsWN4sNeno6sbqVIC2fZ+rAUBFA9ZEUDA==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.11.4(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) + '@reactflow/core': 11.11.4(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) classcat: 5.0.5 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - zustand: 4.5.5(@types/react@18.2.79)(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + zustand: 4.5.5(@types/react@19.2.2)(react@19.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/controls@11.2.14(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@reactflow/controls@11.2.14(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-MiJp5VldFD7FrqaBNIrQ85dxChrG6ivuZ+dcFhPQUwOK3HfYgX2RHdBua+gx+40p5Vw5It3dVNp/my4Z3jF0dw==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.11.4(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) + '@reactflow/core': 11.11.4(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) classcat: 5.0.5 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - zustand: 4.5.5(@types/react@18.2.79)(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + zustand: 4.5.5(@types/react@19.2.2)(react@19.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/core@11.11.4(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@reactflow/core@11.11.4(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-H4vODklsjAq3AMq6Np4LE12i1I4Ta9PrDHuBR9GmL8uzTt2l2jh4CiQbEMpvMDcp7xi4be0hgXj+Ysodde/i7Q==} peerDependencies: react: '>=17' @@ -17217,63 +17770,63 @@ packages: d3-drag: 3.0.0 d3-selection: 3.0.0 d3-zoom: 3.0.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - zustand: 4.5.5(@types/react@18.2.79)(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + zustand: 4.5.5(@types/react@19.2.2)(react@19.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/minimap@11.7.14(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@reactflow/minimap@11.7.14(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-mpwLKKrEAofgFJdkhwR5UQ1JYWlcAAL/ZU/bctBkuNTT1yqV+y0buoNVImsRehVYhJwffSWeSHaBR5/GJjlCSQ==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.11.4(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) + '@reactflow/core': 11.11.4(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) '@types/d3-selection': 3.0.10 '@types/d3-zoom': 3.0.8 classcat: 5.0.5 d3-selection: 3.0.0 d3-zoom: 3.0.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - zustand: 4.5.5(@types/react@18.2.79)(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + zustand: 4.5.5(@types/react@19.2.2)(react@19.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/node-resizer@2.2.14(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@reactflow/node-resizer@2.2.14(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-fwqnks83jUlYr6OHcdFEedumWKChTHRGw/kbCxj0oqBd+ekfs+SIp4ddyNU0pdx96JIm5iNFS0oNrmEiJbbSaA==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.11.4(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) + '@reactflow/core': 11.11.4(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) classcat: 5.0.5 d3-drag: 3.0.0 d3-selection: 3.0.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - zustand: 4.5.5(@types/react@18.2.79)(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + zustand: 4.5.5(@types/react@19.2.2)(react@19.2.0) transitivePeerDependencies: - '@types/react' - immer dev: false - /@reactflow/node-toolbar@1.3.14(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@reactflow/node-toolbar@1.3.14(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-rbynXQnH/xFNu4P9H+hVqlEUafDCkEoCy0Dg9mG22Sg+rY/0ck6KkrAQrYrTgXusd+cEJOMK0uOOFCK2/5rSGQ==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/core': 11.11.4(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) + '@reactflow/core': 11.11.4(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) classcat: 5.0.5 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - zustand: 4.5.5(@types/react@18.2.79)(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + zustand: 4.5.5(@types/react@19.2.2)(react@19.2.0) transitivePeerDependencies: - '@types/react' - immer @@ -20230,7 +20783,7 @@ packages: dependencies: '@mdx-js/loader': 3.1.0(acorn@8.15.0)(webpack@5.98.0) '@mdx-js/mdx': 3.1.0(acorn@8.15.0) - '@mdx-js/react': 3.1.0(@types/react@19.1.8)(react@19.1.1) + '@mdx-js/react': 3.1.0(@types/react@19.1.8)(react@19.2.0) '@rsbuild/core': 1.4.12 '@rsbuild/plugin-react': 1.3.4(@rsbuild/core@1.4.12) '@rspress/mdx-rs': 0.6.6 @@ -20241,7 +20794,7 @@ packages: '@rspress/theme-default': 2.0.0-beta.20 '@shikijs/rehype': 3.6.0 '@types/unist': 3.0.3 - '@unhead/react': 2.0.12(react@19.1.1) + '@unhead/react': 2.0.12(react@19.2.0) enhanced-resolve: 5.18.2 github-slugger: 2.0.0 hast-util-from-html: 2.0.3 @@ -20250,10 +20803,10 @@ packages: lodash-es: 4.17.21 mdast-util-mdxjs-esm: 2.0.1 picocolors: 1.1.1 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) react-lazy-with-preload: 2.2.1 - react-router-dom: 6.30.1(react-dom@19.1.1)(react@19.1.1) + react-router-dom: 6.30.1(react-dom@19.2.0)(react@19.2.0) rehype-external-links: 3.0.0 rehype-raw: 7.0.0 remark: 15.0.1 @@ -20278,7 +20831,7 @@ packages: hasBin: true dependencies: '@mdx-js/mdx': 3.1.1 - '@mdx-js/react': 3.1.1(@types/react@19.1.8)(react@19.1.1) + '@mdx-js/react': 3.1.1(@types/react@19.1.8)(react@19.2.0) '@rsbuild/core': 1.5.16 '@rsbuild/plugin-react': 1.4.1(@rsbuild/core@1.5.16) '@rspress/mdx-rs': 0.6.6 @@ -20287,7 +20840,7 @@ packages: '@rspress/theme-default': 2.0.0-beta.34(@types/react@19.1.8) '@shikijs/rehype': 3.13.0 '@types/unist': 3.0.3 - '@unhead/react': 2.0.19(react@19.1.1) + '@unhead/react': 2.0.19(react@19.2.0) cac: 6.7.14 chokidar: 3.6.0 github-slugger: 2.0.0 @@ -20297,10 +20850,10 @@ packages: mdast-util-mdxjs-esm: 2.0.1 medium-zoom: 1.1.0 picocolors: 1.1.1 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) react-lazy-with-preload: 2.2.1 - react-router-dom: 6.30.1(react-dom@19.1.1)(react@19.1.1) + react-router-dom: 6.30.1(react-dom@19.2.0)(react@19.2.0) rehype-external-links: 3.0.0 rehype-raw: 7.0.0 remark-gfm: 4.0.1 @@ -20442,10 +20995,10 @@ packages: engines: {node: '>=18.0.0'} dependencies: '@rspress/shared': 2.0.0-beta.20 - '@unhead/react': 2.0.12(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) - react-router-dom: 6.30.1(react-dom@19.1.1)(react@19.1.1) + '@unhead/react': 2.0.12(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-router-dom: 6.30.1(react-dom@19.2.0)(react@19.2.0) dev: false /@rspress/runtime@2.0.0-beta.34: @@ -20453,10 +21006,10 @@ packages: engines: {node: '>=18.0.0'} dependencies: '@rspress/shared': 2.0.0-beta.34 - '@unhead/react': 2.0.19(react@19.1.1) - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) - react-router-dom: 6.30.1(react-dom@19.1.1)(react@19.1.1) + '@unhead/react': 2.0.19(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-router-dom: 6.30.1(react-dom@19.2.0)(react@19.2.0) dev: false /@rspress/shared@2.0.0-beta.16: @@ -20493,10 +21046,10 @@ packages: resolution: {integrity: sha512-6FCLVrcKtIGkqMoN0YlR1ZwCAscGvrxfCPVxekXJkDkKEg2go+sIBsamo0z0h7NrI2gzIV8SlouZaQ+CjbdkUg==} engines: {node: '>=18.0.0'} dependencies: - '@mdx-js/react': 2.3.0(react@19.1.1) + '@mdx-js/react': 2.3.0(react@19.2.0) '@rspress/runtime': 2.0.0-beta.20 '@rspress/shared': 2.0.0-beta.20 - '@unhead/react': 2.0.12(react@19.1.1) + '@unhead/react': 2.0.12(react@19.2.0) body-scroll-lock: 4.0.0-beta.0 copy-to-clipboard: 3.3.3 flexsearch: 0.7.43 @@ -20504,8 +21057,8 @@ packages: hast-util-to-jsx-runtime: 2.3.6 lodash-es: 4.17.21 nprogress: 0.2.0 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) shiki: 3.6.0 transitivePeerDependencies: - supports-color @@ -20515,10 +21068,10 @@ packages: resolution: {integrity: sha512-ZnW9oWEA3+lH0nh71bOOncLDiosZRutRXlXSnkjSMJGacBjGITFQc+ECc1E11+tcpIIt0NiWikx7/PeXXjBmAA==} engines: {node: '>=18.0.0'} dependencies: - '@mdx-js/react': 3.1.1(@types/react@19.1.8)(react@19.1.1) + '@mdx-js/react': 3.1.1(@types/react@19.1.8)(react@19.2.0) '@rspress/runtime': 2.0.0-beta.34 '@rspress/shared': 2.0.0-beta.34 - '@unhead/react': 2.0.19(react@19.1.1) + '@unhead/react': 2.0.19(react@19.2.0) body-scroll-lock: 4.0.0-beta.0 copy-to-clipboard: 3.3.3 flexsearch: 0.7.43 @@ -20526,8 +21079,8 @@ packages: hast-util-to-jsx-runtime: 2.3.6 lodash-es: 4.17.21 nprogress: 0.2.0 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) shiki: 3.13.0 transitivePeerDependencies: - '@types/react' @@ -21055,12 +21608,12 @@ packages: - '@types/react' dev: true - /@storybook/addon-docs@9.0.17(@types/react@18.3.11)(storybook@9.0.9): + /@storybook/addon-docs@9.0.17(@types/react@19.2.2)(storybook@9.0.9): resolution: {integrity: sha512-LOX/kKgQGnyulrqZHsvf77+ZoH/nSUaplGr5hvZglW/U6ak6fO9seJyXAzVKEnC6p+F8n02kFBZbi3s+znQhSg==} peerDependencies: storybook: ^9.0.17 dependencies: - '@mdx-js/react': 3.1.0(@types/react@18.3.11)(react@18.3.1) + '@mdx-js/react': 3.1.0(@types/react@19.2.2)(react@18.3.1) '@storybook/csf-plugin': 9.0.17(storybook@9.0.9) '@storybook/icons': 1.4.0(react-dom@18.3.1)(react@18.3.1) '@storybook/react-dom-shim': 9.0.17(react-dom@18.3.1)(react@18.3.1)(storybook@9.0.9) @@ -21255,23 +21808,23 @@ packages: - supports-color dev: true - /@storybook/components@7.6.20(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /@storybook/components@7.6.20(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-0d8u4m558R+W5V+rseF/+e9JnMciADLXTpsILrG+TBhwECk0MctIWW18bkqkujdCm8kDZr5U2iM/5kS1Noy7Ug==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@radix-ui/react-select': 1.2.2(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-toolbar': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-select': 1.2.2(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@radix-ui/react-toolbar': 1.1.0(@types/react-dom@19.2.2)(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) '@storybook/client-logger': 7.6.20 '@storybook/csf': 0.1.12 '@storybook/global': 5.0.0 - '@storybook/theming': 7.6.20(react-dom@18.3.1)(react@18.3.1) + '@storybook/theming': 7.6.20(react-dom@19.2.0)(react@19.2.0) '@storybook/types': 7.6.20 memoizerific: 1.11.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - use-resize-observer: 9.1.0(react-dom@18.3.1)(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + use-resize-observer: 9.1.0(react-dom@19.2.0)(react@19.2.0) util-deprecate: 1.0.2 transitivePeerDependencies: - '@types/react' @@ -21579,11 +22132,11 @@ packages: resolution: {integrity: sha512-0Cf6WN0t7yEG2DR29tN5j+i7H/TH5EfPppg9h9/KiQSoFHk+6KLoy2p5do94acFU+Ro4+zzxvdCGbcYGKuArpg==} dev: true - /@storybook/mdx1-csf@1.0.0(react@18.3.1): + /@storybook/mdx1-csf@1.0.0(react@19.2.0): resolution: {integrity: sha512-sZFncpLnsqLQPItRjL31UWuA8jTcsm05ab5nwG4sx9oodTekK4C1AUYY3R3Z1hbvPbGlY7hmuA8aM7Qye3u7TA==} dependencies: '@mdx-js/mdx': 1.6.22 - '@mdx-js/react': 1.6.22(react@18.3.1) + '@mdx-js/react': 1.6.22(react@19.2.0) transitivePeerDependencies: - react - supports-color @@ -21793,14 +22346,14 @@ packages: - supports-color dev: true - /@storybook/react-dom-shim@7.6.20(react-dom@18.3.1)(react@18.3.1): + /@storybook/react-dom-shim@7.6.20(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-SRvPDr9VWcS24ByQOVmbfZ655y5LvjXRlsF1I6Pr9YZybLfYbu3L5IicfEHT4A8lMdghzgbPFVQaJez46DTrkg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true /@storybook/react-dom-shim@8.6.12(react-dom@18.3.1)(react@18.3.1)(storybook@8.4.2): @@ -21863,7 +22416,7 @@ packages: storybook: 8.4.2(prettier@3.3.3) dev: true - /@storybook/react@7.6.20(encoding@0.1.13)(react-dom@18.3.1)(react@18.3.1)(typescript@5.0.4): + /@storybook/react@7.6.20(encoding@0.1.13)(react-dom@19.2.0)(react@19.2.0)(typescript@5.0.4): resolution: {integrity: sha512-i5tKNgUbTNwlqBWGwPveDhh9ktlS0wGtd97A1ZgKZc3vckLizunlAFc7PRC1O/CMq5PTyxbuUb4RvRD2jWKwDA==} engines: {node: '>=16.0.0'} peerDependencies: @@ -21879,7 +22432,7 @@ packages: '@storybook/docs-tools': 7.6.20(encoding@0.1.13) '@storybook/global': 5.0.0 '@storybook/preview-api': 7.6.20 - '@storybook/react-dom-shim': 7.6.20(react-dom@18.3.1)(react@18.3.1) + '@storybook/react-dom-shim': 7.6.20(react-dom@19.2.0)(react@19.2.0) '@storybook/types': 7.6.20 '@types/escodegen': 0.0.6 '@types/estree': 0.0.51 @@ -21891,9 +22444,9 @@ packages: html-tags: 3.3.1 lodash: 4.17.21 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-element-to-jsx-string: 15.0.0(react-dom@18.3.1)(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-element-to-jsx-string: 15.0.0(react-dom@19.2.0)(react@19.2.0) ts-dedent: 2.2.0 type-fest: 2.19.0 typescript: 5.0.4 @@ -21974,18 +22527,18 @@ packages: - supports-color dev: true - /@storybook/theming@7.6.20(react-dom@18.3.1)(react@18.3.1): + /@storybook/theming@7.6.20(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-iT1pXHkSkd35JsCte6Qbanmprx5flkqtSHC6Gi6Umqoxlg9IjiLPmpHbaIXzoC06DSW93hPj5Zbi1lPlTvRC7Q==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@18.3.1) + '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@19.2.0) '@storybook/client-logger': 7.6.20 '@storybook/global': 5.0.0 memoizerific: 1.11.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true /@storybook/theming@8.6.12(storybook@8.4.2): @@ -22667,7 +23220,7 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: true - /@testing-library/react@16.1.0(@testing-library/dom@10.4.1)(@types/react@18.3.11)(react-dom@18.3.1)(react@18.3.1): + /@testing-library/react@16.1.0(@testing-library/dom@10.4.1)(@types/react@19.2.2)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-Q2ToPvg0KsVL0ohND9A3zLJWcOXXcO8IDu3fj11KhNt0UlCWyFyvnCIBkd12tidB2lkiVRG8VFqdhcqhqnAQtg==} engines: {node: '>=18'} peerDependencies: @@ -22684,7 +23237,7 @@ packages: dependencies: '@babel/runtime': 7.28.2 '@testing-library/dom': 10.4.1 - '@types/react': 18.3.11 + '@types/react': 19.2.2 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: true @@ -22998,6 +23551,10 @@ packages: resolution: {integrity: sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==} dev: false + /@types/d3-timer@2.0.3: + resolution: {integrity: sha512-jhAJzaanK5LqyLQ50jJNIrB8fjL9gwWZTgYjevPvkDLMU+kTAZkYsobI59nYoeSrH1PucuyJEi247Pb90t6XUg==} + dev: false + /@types/d3-timer@3.0.2: resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} dev: false @@ -23233,7 +23790,7 @@ packages: /@types/hoist-non-react-statics@3.3.5: resolution: {integrity: sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==} dependencies: - '@types/react': 18.3.11 + '@types/react': 19.2.2 hoist-non-react-statics: 3.3.2 /@types/html-minifier-terser@6.1.0: @@ -23335,7 +23892,7 @@ packages: /@types/loadable__component@5.13.9: resolution: {integrity: sha512-QWOtIkwZqHNdQj3nixQ8oyihQiTMKZLk/DNuvNxMSbTfxf47w+kqcbnxlUeBgAxdOtW0Dh48dTAIp83iJKtnrQ==} dependencies: - '@types/react': 18.3.11 + '@types/react': 19.2.2 /@types/lodash-es@4.17.12: resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} @@ -23499,10 +24056,18 @@ packages: '@types/react': 19.1.8 dev: true + /@types/react-dom@19.2.2(@types/react@19.2.2): + resolution: {integrity: sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==} + peerDependencies: + '@types/react': ^19.2.0 + dependencies: + '@types/react': 19.2.2 + dev: true + /@types/react-helmet@6.1.11: resolution: {integrity: sha512-0QcdGLddTERotCXo3VFlUSWO3ztraw8nZ6e3zJSgG7apwV5xt+pJUS8ewPBqT4NYB1optGLprNQzFleIY84u/g==} dependencies: - '@types/react': 18.3.11 + '@types/react': 19.2.2 /@types/react-router-dom@5.3.3: resolution: {integrity: sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==} @@ -23515,7 +24080,7 @@ packages: resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==} dependencies: '@types/history': 4.7.11 - '@types/react': 18.3.11 + '@types/react': 19.2.2 /@types/react-test-renderer@19.1.0: resolution: {integrity: sha512-XD0WZrHqjNrxA/MaR9O22w/RNidWR9YZmBdRGI7wcnWGrv/3dA8wKCJ8m63Sn+tLJhcjmuhOi629N66W6kgWzQ==} @@ -23548,6 +24113,11 @@ packages: dependencies: csstype: 3.1.3 + /@types/react@19.2.2: + resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==} + dependencies: + csstype: 3.1.3 + /@types/resolve@1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} dependencies: @@ -23624,7 +24194,7 @@ packages: resolution: {integrity: sha512-mmiVvwpYklFIv9E8qfxuPyIt/OuyIrn6gMOAMOFUO3WJfSrSE+sGUoa4PiZj77Ut7bKZpaa6o1fBKS/4TOEvnA==} dependencies: '@types/hoist-non-react-statics': 3.3.5 - '@types/react': 18.3.11 + '@types/react': 19.2.2 csstype: 3.1.3 /@types/stylis@4.2.0: @@ -24284,21 +24854,21 @@ packages: /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - /@unhead/react@2.0.12(react@19.1.1): + /@unhead/react@2.0.12(react@19.2.0): resolution: {integrity: sha512-2qRwLtPVUDWHIP2n3S3gL0jT+Wcalb0huCgf/GFXYhV8ZWqm+5+ZTLVlPN7O5q3aVhIGO2gZHsppXNVq+L3fuQ==} peerDependencies: react: '>=18' dependencies: - react: 19.1.1 + react: 19.2.0 unhead: 2.0.12 dev: false - /@unhead/react@2.0.19(react@19.1.1): + /@unhead/react@2.0.19(react@19.2.0): resolution: {integrity: sha512-pW00tkOneGGTEJp5UeVkVWmti4VecLj0rIje5AqcBs0AoglSxc18LGGKi9Exd098++GzVouhkGo1Ch02YnZS7g==} peerDependencies: react: '>=18.3.1' dependencies: - react: 19.1.1 + react: 19.2.0 unhead: 2.0.19 dev: false @@ -26080,7 +26650,7 @@ packages: indent-string: 5.0.0 dev: true - /ahooks@3.8.1(react@18.3.1): + /ahooks@3.8.1(react@19.2.0): resolution: {integrity: sha512-JoP9+/RWO7MnI/uSKdvQ8WB10Y3oo1PjLv+4Sv4Vpm19Z86VUMdXh+RhWvMGxZZs06sq2p0xVtFk8Oh5ZObsoA==} engines: {node: '>=8.0.0'} peerDependencies: @@ -26091,7 +26661,7 @@ packages: intersection-observer: 0.12.2 js-cookie: 3.0.5 lodash: 4.17.21 - react: 18.3.1 + react: 19.2.0 react-fast-compare: 3.2.2 resize-observer-polyfill: 1.5.1 screenfull: 5.2.0 @@ -29947,6 +30517,10 @@ packages: engines: {node: '>=12'} dev: false + /d3-dispatch@2.0.0: + resolution: {integrity: sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==} + dev: false + /d3-dispatch@3.0.1: resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} engines: {node: '>=12'} @@ -29960,11 +30534,23 @@ packages: d3-selection: 3.0.0 dev: false + /d3-ease@1.0.7: + resolution: {integrity: sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==} + dev: false + /d3-ease@3.0.1: resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} engines: {node: '>=12'} dev: false + /d3-force@2.1.1: + resolution: {integrity: sha512-nAuHEzBqMvpFVMf9OX75d00OxvOXdxY+xECIXjW6Gv8BRrXu6gAWbv/9XKrvfJ5i5DCokDW7RYE50LRoK092ew==} + dependencies: + d3-dispatch: 2.0.0 + d3-quadtree: 2.0.0 + d3-timer: 2.0.0 + dev: false + /d3-interpolate@3.0.1: resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} engines: {node: '>=12'} @@ -29972,11 +30558,23 @@ packages: d3-color: 3.1.0 dev: false + /d3-quadtree@2.0.0: + resolution: {integrity: sha512-b0Ed2t1UUalJpc3qXzKi+cPGxeXRr4KU9YSlocN74aTzp6R/Ud43t79yLLqxHRWZfsvWXmbDWPpoENK1K539xw==} + dev: false + /d3-selection@3.0.0: resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} engines: {node: '>=12'} dev: false + /d3-timer@1.0.10: + resolution: {integrity: sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==} + dev: false + + /d3-timer@2.0.0: + resolution: {integrity: sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==} + dev: false + /d3-timer@3.0.1: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} @@ -30015,6 +30613,15 @@ packages: type: 2.7.3 dev: false + /dagre-compound@0.0.11(dagre@0.8.5): + resolution: {integrity: sha512-UrSgRP9LtOZCYb9e5doolZXpc7xayyszgyOs7uakTK4n4KsLegLVTRRtq01GpQd/iZjYw5fWMapx9ed+c80MAQ==} + engines: {node: '>=6.0.0'} + peerDependencies: + dagre: ^0.8.5 + dependencies: + dagre: 0.8.5 + dev: false + /dagre@0.8.5: resolution: {integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==} dependencies: @@ -30445,6 +31052,10 @@ packages: repeat-string: 1.6.1 dev: true + /detect-browser@5.3.0: + resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==} + dev: false + /detect-file@1.0.0: resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} engines: {node: '>=0.10.0'} @@ -32973,6 +33584,10 @@ packages: dependencies: picomatch: 4.0.3 + /fecha@4.2.3: + resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + dev: false + /fetch-blob@3.2.0: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} @@ -33908,6 +34523,14 @@ packages: resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} dev: false + /gl-matrix@3.4.4: + resolution: {integrity: sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==} + dev: false + + /gl-vec2@1.3.0: + resolution: {integrity: sha512-YiqaAuNsheWmUV0Sa8k94kBB0D6RWjwZztyO+trEYS8KzJ6OQB/4686gdrf59wld4hHFIvaxynO3nRxpk1Ij/A==} + dev: false + /glob-base@0.3.0: resolution: {integrity: sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==} engines: {node: '>=0.10.0'} @@ -35406,6 +36029,10 @@ packages: - '@types/node' dev: true + /insert-css@2.0.0: + resolution: {integrity: sha512-xGq5ISgcUP5cvGkS2MMFLtPDBtrtQPSFfC6gA6U8wHKqfjTIMZLZNxOItQnoSjdOzlXOLU/yD32RKC4SvjNbtA==} + dev: false + /inspect-with-kind@1.0.5: resolution: {integrity: sha512-MAQUJuIo7Xqk8EVNP+6d3CKq9c80hi4tjIbIAT6lmGW9W6WzlHiu9PS8uSuUYU+Do+j1baiFp3H25XEVxDIG2g==} dependencies: @@ -35488,6 +36115,10 @@ packages: is-decimal: 2.0.1 dev: false + /is-any-array@2.0.1: + resolution: {integrity: sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==} + dev: false + /is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} @@ -39350,6 +39981,39 @@ packages: hasBin: true dev: true + /ml-array-max@1.2.4: + resolution: {integrity: sha512-BlEeg80jI0tW6WaPyGxf5Sa4sqvcyY6lbSn5Vcv44lp1I2GR6AWojfUvLnGTNsIXrZ8uqWmo8VcG1WpkI2ONMQ==} + dependencies: + is-any-array: 2.0.1 + dev: false + + /ml-array-min@1.2.3: + resolution: {integrity: sha512-VcZ5f3VZ1iihtrGvgfh/q0XlMobG6GQ8FsNyQXD3T+IlstDv85g8kfV0xUG1QPRO/t21aukaJowDzMTc7j5V6Q==} + dependencies: + is-any-array: 2.0.1 + dev: false + + /ml-array-rescale@1.3.7: + resolution: {integrity: sha512-48NGChTouvEo9KBctDfHC3udWnQKNKEWN0ziELvY3KG25GR5cA8K8wNVzracsqSW1QEkAXjTNx+ycgAv06/1mQ==} + dependencies: + is-any-array: 2.0.1 + ml-array-max: 1.2.4 + ml-array-min: 1.2.3 + dev: false + + /ml-matrix@6.12.1: + resolution: {integrity: sha512-TJ+8eOFdp+INvzR4zAuwBQJznDUfktMtOB6g/hUcGh3rcyjxbz4Te57Pgri8Q9bhSQ7Zys4IYOGhFdnlgeB6Lw==} + dependencies: + is-any-array: 2.0.1 + ml-array-rescale: 1.3.7 + dev: false + + /ml-matrix@6.5.0: + resolution: {integrity: sha512-sms732Dge+rs5dU4mnjE0oqLWm1WujvR2fr38LgUHRG2cjXjWlO3WJupLYaSz3++2iYr0UrGDK72OAivr3J8dg==} + dependencies: + ml-array-rescale: 1.3.7 + dev: false + /mlly@1.6.1: resolution: {integrity: sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==} dependencies: @@ -42875,6 +43539,15 @@ packages: parse-ms: 4.0.0 dev: true + /probe.gl@3.6.0: + resolution: {integrity: sha512-19JydJWI7+DtR4feV+pu4Mn1I5TAc0xojuxVgZdXIyfmTLfUaFnk4OloWK1bKbPtkgGKLr2lnbnCXmpZEcEp9g==} + dependencies: + '@babel/runtime': 7.28.2 + '@probe.gl/env': 3.6.0 + '@probe.gl/log': 3.6.0 + '@probe.gl/stats': 3.6.0 + dev: false + /proc-log@3.0.0: resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -44740,13 +45413,13 @@ packages: strip-json-comments: 2.0.1 dev: true - /react-clientside-effect@1.2.6(react@18.3.1): + /react-clientside-effect@1.2.6(react@19.2.0): resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==} peerDependencies: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 dependencies: '@babel/runtime': 7.28.2 - react: 18.3.1 + react: 19.2.0 dev: false /react-confetti@6.1.0(react@18.3.1): @@ -44867,7 +45540,15 @@ packages: scheduler: 0.26.0 dev: false - /react-element-to-jsx-string@15.0.0(react-dom@18.3.1)(react@18.3.1): + /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 + + /react-element-to-jsx-string@15.0.0(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==} peerDependencies: react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0 @@ -44875,8 +45556,8 @@ packages: dependencies: '@base2/pretty-print-object': 1.0.1 is-plain-object: 5.0.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) react-is: 18.1.0 dev: true @@ -44911,7 +45592,7 @@ packages: /react-fast-compare@3.2.2: resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} - /react-focus-lock@2.13.2(@types/react@18.2.79)(react@18.3.1): + /react-focus-lock@2.13.2(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-T/7bsofxYqnod2xadvuwjGKHOoL5GH7/EIPI5UyEvaU/c2CcphvGI371opFtuY/SYdbMsNiuF4HsHQ50nA/TKQ==} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -44921,13 +45602,13 @@ packages: optional: true dependencies: '@babel/runtime': 7.28.2 - '@types/react': 18.2.79 + '@types/react': 19.2.2 focus-lock: 1.3.5 prop-types: 15.8.1 - react: 18.3.1 - react-clientside-effect: 1.2.6(react@18.3.1) - use-callback-ref: 1.3.2(@types/react@18.2.79)(react@18.3.1) - use-sidecar: 1.1.2(@types/react@18.2.79)(react@18.3.1) + react: 19.2.0 + react-clientside-effect: 1.2.6(react@19.2.0) + use-callback-ref: 1.3.2(@types/react@19.2.2)(react@19.2.0) + use-sidecar: 1.1.2(@types/react@19.2.2)(react@19.2.0) dev: false /react-helmet@6.1.0(react@18.3.1): @@ -44941,6 +45622,17 @@ packages: react-fast-compare: 3.2.2 react-side-effect: 2.1.2(react@18.3.1) + /react-helmet@6.1.0(react@19.2.0): + resolution: {integrity: sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==} + peerDependencies: + react: '>=16.3.0' + dependencies: + object-assign: 4.1.1 + prop-types: 15.8.1 + react: 19.2.0 + react-fast-compare: 3.2.2 + react-side-effect: 2.1.2(react@19.2.0) + /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -45085,7 +45777,7 @@ packages: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} - /react-remove-scroll-bar@2.3.6(@types/react@18.2.79)(react@18.3.1): + /react-remove-scroll-bar@2.3.6(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} engines: {node: '>=10'} peerDependencies: @@ -45095,13 +45787,13 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.79 - react: 18.3.1 - react-style-singleton: 2.2.1(@types/react@18.2.79)(react@18.3.1) + '@types/react': 19.2.2 + react: 19.2.0 + react-style-singleton: 2.2.1(@types/react@19.2.2)(react@19.2.0) tslib: 2.8.1 dev: true - /react-remove-scroll@2.5.5(@types/react@18.2.79)(react@18.3.1): + /react-remove-scroll@2.5.5(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} engines: {node: '>=10'} peerDependencies: @@ -45111,13 +45803,13 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.79 - react: 18.3.1 - react-remove-scroll-bar: 2.3.6(@types/react@18.2.79)(react@18.3.1) - react-style-singleton: 2.2.1(@types/react@18.2.79)(react@18.3.1) + '@types/react': 19.2.2 + react: 19.2.0 + react-remove-scroll-bar: 2.3.6(@types/react@19.2.2)(react@19.2.0) + react-style-singleton: 2.2.1(@types/react@19.2.2)(react@19.2.0) tslib: 2.8.1 - use-callback-ref: 1.3.2(@types/react@18.2.79)(react@18.3.1) - use-sidecar: 1.1.2(@types/react@18.2.79)(react@18.3.1) + use-callback-ref: 1.3.2(@types/react@19.2.2)(react@19.2.0) + use-sidecar: 1.1.2(@types/react@19.2.2)(react@19.2.0) dev: true /react-router-dom@5.3.4(react@17.0.2): @@ -45201,7 +45893,19 @@ packages: react-dom: 18.3.1(react@18.3.1) react-router: 6.27.0(react@18.3.1) - /react-router-dom@6.30.1(react-dom@19.1.1)(react@19.1.1): + /react-router-dom@6.27.0(react-dom@19.2.0)(react@19.2.0): + resolution: {integrity: sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + '@remix-run/router': 1.20.0 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-router: 6.27.0(react@19.2.0) + + /react-router-dom@6.30.1(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==} engines: {node: '>=14.0.0'} peerDependencies: @@ -45209,9 +45913,9 @@ packages: react-dom: '>=16.8' dependencies: '@remix-run/router': 1.23.0 - react: 19.1.1 - react-dom: 19.1.1(react@19.1.1) - react-router: 6.30.1(react@19.1.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-router: 6.30.1(react@19.2.0) dev: false /react-router@5.3.4(react@17.0.2): @@ -45297,14 +46001,23 @@ packages: '@remix-run/router': 1.20.0 react: 18.3.1 - /react-router@6.30.1(react@19.1.1): + /react-router@6.27.0(react@19.2.0): + resolution: {integrity: sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + dependencies: + '@remix-run/router': 1.20.0 + react: 19.2.0 + + /react-router@6.30.1(react@19.2.0): resolution: {integrity: sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' dependencies: '@remix-run/router': 1.23.0 - react: 19.1.1 + react: 19.2.0 dev: false /react-router@7.9.4(react-dom@18.3.1)(react@18.3.1): @@ -45352,7 +46065,14 @@ packages: dependencies: react: 18.3.1 - /react-style-singleton@2.2.1(@types/react@18.2.79)(react@18.3.1): + /react-side-effect@2.1.2(react@19.2.0): + resolution: {integrity: sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==} + peerDependencies: + react: ^16.3.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 19.2.0 + + /react-style-singleton@2.2.1(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} engines: {node: '>=10'} peerDependencies: @@ -45362,10 +46082,10 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.79 + '@types/react': 19.2.2 get-nonce: 1.0.1 invariant: 2.2.4 - react: 18.3.1 + react: 19.2.0 tslib: 2.8.1 dev: true @@ -45390,7 +46110,7 @@ packages: scheduler: 0.26.0 dev: true - /react-transition-group@4.4.5(react-dom@18.3.1)(react@18.3.1): + /react-transition-group@4.4.5(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} peerDependencies: react: '>=16.6.0' @@ -45400,8 +46120,8 @@ packages: dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: false /react@17.0.2: @@ -45436,20 +46156,24 @@ packages: engines: {node: '>=0.10.0'} dev: false - /reactflow@11.11.4(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1): + /react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} + engines: {node: '>=0.10.0'} + + /reactflow@11.11.4(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-70FOtJkUWH3BAOsN+LU9lCrKoKbtOPnz2uq0CV2PLdNSwxTXOhCbsZr50GmZ+Rtw3jx8Uv7/vBFtCGixLfd4Og==} peerDependencies: react: '>=17' react-dom: '>=17' dependencies: - '@reactflow/background': 11.3.14(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@reactflow/controls': 11.2.14(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@reactflow/core': 11.11.4(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@reactflow/minimap': 11.7.14(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@reactflow/node-resizer': 2.2.14(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - '@reactflow/node-toolbar': 1.3.14(@types/react@18.2.79)(react-dom@18.3.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@reactflow/background': 11.3.14(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@reactflow/controls': 11.2.14(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@reactflow/core': 11.11.4(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@reactflow/minimap': 11.7.14(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@reactflow/node-resizer': 2.2.14(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + '@reactflow/node-toolbar': 1.3.14(@types/react@19.2.2)(react-dom@19.2.0)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) transitivePeerDependencies: - '@types/react' - immer @@ -45796,6 +46520,10 @@ packages: dependencies: jsesc: 3.0.2 + /regl@1.7.0: + resolution: {integrity: sha512-bEAtp/qrtKucxXSJkD4ebopFZYP0q1+3Vb2WECWv/T8yQEgKxDxJ7ztO285tAMaYZVR6mM1GgI6CCn8FROtL1w==} + dev: false + /rehype-external-links@3.0.0: resolution: {integrity: sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==} dependencies: @@ -47135,6 +47863,9 @@ packages: /scheduler@0.26.0: resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + /scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + /schema-utils@3.3.0: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} @@ -48657,6 +49388,30 @@ packages: transitivePeerDependencies: - '@babel/core' + /styled-components@5.3.11(@babel/core@7.28.0)(react-dom@19.2.0)(react-is@18.3.1)(react@19.2.0): + resolution: {integrity: sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==} + engines: {node: '>=10'} + peerDependencies: + react: '>= 16.8.0' + react-dom: '>= 16.8.0' + react-is: '>= 16.8.0' + dependencies: + '@babel/helper-module-imports': 7.27.1(supports-color@5.5.0) + '@babel/traverse': 7.28.0(supports-color@5.5.0) + '@emotion/is-prop-valid': 1.3.1 + '@emotion/stylis': 0.8.5 + '@emotion/unitless': 0.7.5 + babel-plugin-styled-components: 2.1.4(@babel/core@7.28.0)(styled-components@5.3.11)(supports-color@5.5.0) + css-to-react-native: 3.2.0 + hoist-non-react-statics: 3.3.2 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-is: 18.3.1 + shallowequal: 1.1.0 + supports-color: 5.5.0 + transitivePeerDependencies: + - '@babel/core' + /styled-components@6.1.8(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-PQ6Dn+QxlWyEGCKDS71NGsXoVLKfE1c3vApkvDYS5KAK+V8fNWGhbSUEo9Gg2iaID2tjLXegEW3bZDUGpofRWw==} engines: {node: '>= 16'} @@ -49625,6 +50380,10 @@ packages: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} dev: true + /tinycolor2@1.6.0: + resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + dev: false + /tinyexec@0.3.0: resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==} dev: true @@ -51153,7 +51912,7 @@ packages: qs: 6.14.0 dev: true - /use-callback-ref@1.3.2(@types/react@18.2.79)(react@18.3.1): + /use-callback-ref@1.3.2(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} engines: {node: '>=10'} peerDependencies: @@ -51163,8 +51922,8 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.79 - react: 18.3.1 + '@types/react': 19.2.2 + react: 19.2.0 tslib: 2.8.1 /use-count-up@3.0.1(react@19.0.0-rc-cd22717c-20241013): @@ -51184,18 +51943,18 @@ packages: react: 19.0.0-rc-cd22717c-20241013 dev: false - /use-resize-observer@9.1.0(react-dom@18.3.1)(react@18.3.1): + /use-resize-observer@9.1.0(react-dom@19.2.0)(react@19.2.0): resolution: {integrity: sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==} peerDependencies: react: 16.8.0 - 18 react-dom: 16.8.0 - 18 dependencies: '@juggle/resize-observer': 3.4.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) dev: true - /use-sidecar@1.1.2(@types/react@18.2.79)(react@18.3.1): + /use-sidecar@1.1.2(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} engines: {node: '>=10'} peerDependencies: @@ -51205,17 +51964,17 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.79 + '@types/react': 19.2.2 detect-node-es: 1.1.0 - react: 18.3.1 + react: 19.2.0 tslib: 2.8.1 - /use-sync-external-store@1.2.2(react@18.3.1): + /use-sync-external-store@1.2.2(react@19.2.0): resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - react: 18.3.1 + react: 19.2.0 dev: false /use@3.1.1: @@ -53341,7 +54100,7 @@ packages: resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} dev: true - /zustand@4.5.5(@types/react@18.2.79)(react@18.3.1): + /zustand@4.5.5(@types/react@19.2.2)(react@19.2.0): resolution: {integrity: sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==} engines: {node: '>=12.7.0'} peerDependencies: @@ -53356,9 +54115,9 @@ packages: react: optional: true dependencies: - '@types/react': 18.2.79 - react: 18.3.1 - use-sync-external-store: 1.2.2(react@18.3.1) + '@types/react': 19.2.2 + react: 19.2.0 + use-sync-external-store: 1.2.2(react@19.2.0) dev: false /zwitch@1.0.5: