diff --git a/backend/routes/themes.py b/backend/routes/themes.py index 2731e88..b93da0f 100644 --- a/backend/routes/themes.py +++ b/backend/routes/themes.py @@ -25,6 +25,18 @@ async def theme_list( ) +@router.get("/graph", summary="热点穿透:题材-股票网状关系图") +async def theme_graph( + sort_field: int = Query(1, description="题材排序:1=涨幅 4=热度"), + top: int = Query(30, ge=1, le=60, description="题材数量"), +): + if sort_field not in (1, 4): + raise HTTPException(status_code=400, detail="排序字段仅支持 1(涨幅)/4(热度)") + + result = await themes.fetch_theme_graph(sort_field, top) + return JSONResponse(result, headers=_NO_CACHE_HEADERS) + + @router.get("/{theme_code}/detail", summary="题材详情") async def theme_detail(theme_code: str): data = await themes.fetch_theme_detail(theme_code) diff --git a/backend/services/themes.py b/backend/services/themes.py index 0eca9fd..248f87b 100644 --- a/backend/services/themes.py +++ b/backend/services/themes.py @@ -221,3 +221,103 @@ async def fetch_theme_stocks(theme_code: str) -> dict: if ttl > 0: set_cache(cache_key, json.dumps(result, ensure_ascii=False), ttl_hours=ttl) return result + + +# ---- 热点穿透:题材-股票 网状关系图数据 ---- + +# 合并采样:涨幅榜 Top N + 热度榜 Top N 去重合并, +# 避免单一榜单导致股票覆盖题材数被低估(如有研新材覆盖 10+ 题材,仅涨幅榜只能采到 2 个)。 +_GRAPH_MERGE_TOP = 50 + + +async def fetch_theme_graph(sort_field: int = 1, top_n: int = 30) -> dict: + """构建题材-股票网状关系图数据(热点穿透) + + 合并采样涨幅榜 + 热度榜 Top N 题材(去重),并发拉取每题材全部股票, + 统计每股覆盖的题材数(M:N 关系),返回前端可直接渲染的图结构。 + + Args: + sort_field: 题材排序 1=涨幅, 4=热度(当前榜在前,另一榜合并补充) + top_n: 每个榜单的题材数量(1-60) + + Returns: + { + "themes": [{themeCode, themeName, bf3, hotValue, strengthValue, stockCount}], + "stocks": [{securityCode, securityName, coverCount, f3, f2, f62, f100, themeCodes[]}], + "edges": [{themeCode, securityCode}], + "stats": {themeCount, stockCount, coreCount, maxCover} + } + """ + cache_key = f"theme_graph:{sort_field}:{top_n}" + cached = get_cache(cache_key) + if cached is not None: + return json.loads(cached) + + # 1. 合并采样涨幅榜 + 热度榜(当前榜优先在前,另一榜补充),按 themeCode 去重 + primary_list = await fetch_theme_list(sort_field, asc=False) + other_field = 4 if sort_field == 1 else 1 + other_list = await fetch_theme_list(other_field, asc=False) + merged: dict[str, dict] = {} + for t in primary_list[:top_n]: + merged.setdefault(t["themeCode"], t) + for t in other_list[:top_n]: + merged.setdefault(t["themeCode"], t) + themes = list(merged.values()) + if not themes: + return {"themes": [], "stocks": [], "edges": [], "stats": {}} + + # 2. 并发拉取每题材股票(限流保护) + sem = asyncio.Semaphore(5) + + async def _fetch_with_limit(code: str): + async with sem: + return await fetch_theme_stocks(code) + + results = await asyncio.gather(*[_fetch_with_limit(t["themeCode"]) for t in themes]) + + # 3. 构建图数据 + theme_map = {t["themeCode"]: t for t in themes} + stock_map: dict[str, dict] = {} # securityCode -> stock dict + edges: list[dict] = [] + + for t, res in zip(themes, results): + stock_list = res.get("stockList", []) + theme_map[t["themeCode"]]["stockCount"] = len(stock_list) + for s in stock_list: + code = s["securityCode"] + edges.append({"themeCode": t["themeCode"], "securityCode": code}) + if code not in stock_map: + stock_map[code] = { + "securityCode": code, + "securityName": s.get("securityName", ""), + "coverCount": 0, + "f3": s.get("f3"), + "f2": s.get("f2"), + "f62": s.get("f62"), + "f100": s.get("f100", ""), + "themeCodes": [], + } + stock_map[code]["coverCount"] += 1 + stock_map[code]["themeCodes"].append(t["themeCode"]) + + # 4. 排序:覆盖题材数越多(穿透越强)排越前 + stocks = sorted(stock_map.values(), key=lambda x: (-x["coverCount"], -(x.get("f3") or 0))) + + stats = { + "themeCount": len(themes), + "stockCount": len(stocks), + "coreCount": sum(1 for s in stocks if s["coverCount"] >= 2), + "maxCover": max((s["coverCount"] for s in stocks), default=1), + } + + result = { + "themes": list(theme_map.values()), + "stocks": stocks, + "edges": edges, + "stats": stats, + } + + ttl = _dynamic_ttl() + if ttl > 0: + set_cache(cache_key, json.dumps(result, ensure_ascii=False), ttl_hours=ttl) + return result diff --git a/package.json b/package.json index 4589426..48c0e9e 100755 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", + "d3-force": "^3.0.0", "date-fns": "^4.4.0", "embla-carousel-react": "^8.6.0", "framer-motion": "^11.18.2", @@ -64,6 +65,7 @@ "zod": "^3.25.76" }, "devDependencies": { + "@types/d3-force": "^3.0.10", "@types/node": "^22.20.0", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e2c4f2e..4c911b6 100755 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,82 +13,82 @@ importers: version: 5.4.0(react-hook-form@7.81.0(react@19.2.7)) '@radix-ui/react-accordion': specifier: ^1.2.15 - version: 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.2.15(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-alert-dialog': specifier: ^1.1.18 - version: 1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-aspect-ratio': specifier: ^1.1.11 - version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-avatar': specifier: ^1.2.1 - version: 1.2.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.2.1(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-checkbox': specifier: ^1.3.6 - version: 1.3.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.3.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-collapsible': specifier: ^1.1.15 - version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-context-menu': specifier: ^2.3.2 - version: 2.3.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 2.3.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-dialog': specifier: ^1.1.18 - version: 1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-dropdown-menu': specifier: ^2.1.19 - version: 2.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 2.1.19(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-hover-card': specifier: ^1.1.18 - version: 1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-label': specifier: ^2.1.11 - version: 2.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 2.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-menubar': specifier: ^1.1.19 - version: 1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.19(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-navigation-menu': specifier: ^1.2.17 - version: 1.2.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.2.17(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-popover': specifier: ^1.1.18 - version: 1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-progress': specifier: ^1.1.11 - version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-radio-group': specifier: ^1.4.2 - version: 1.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.4.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-scroll-area': specifier: ^1.2.13 - version: 1.2.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.2.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-select': specifier: ^2.3.2 - version: 2.3.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 2.3.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-separator': specifier: ^1.1.11 - version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slider': specifier: ^1.4.2 - version: 1.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.4.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': specifier: ^1.3.0 version: 1.3.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-switch': specifier: ^1.3.2 - version: 1.3.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.3.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-tabs': specifier: ^1.1.16 - version: 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-toggle': specifier: ^1.1.13 - version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-toggle-group': specifier: ^1.1.14 - version: 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-tooltip': specifier: ^1.2.11 - version: 1.2.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.2.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@tailwindcss/vite': specifier: ^4.3.2 version: 4.3.2(vite@7.3.6(@types/node@22.20.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.5)) @@ -109,7 +109,10 @@ importers: version: 2.1.1 cmdk: specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.1(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + d3-force: + specifier: ^3.0.0 + version: 3.0.0 date-fns: specifier: ^4.4.0 version: 4.4.0 @@ -157,7 +160,7 @@ importers: version: 1.4.0 vaul: specifier: ^1.1.2 - version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 1.1.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) vite-tsconfig-paths: specifier: ^6.1.1 version: 6.1.1(typescript@5.9.3)(vite@7.3.6(@types/node@22.20.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.5)) @@ -165,6 +168,9 @@ importers: specifier: ^3.25.76 version: 3.25.76 devDependencies: + '@types/d3-force': + specifier: ^3.0.10 + version: 3.0.10 '@types/node': specifier: ^22.20.0 version: 22.20.0 @@ -173,7 +179,7 @@ importers: version: 19.2.17 '@types/react-dom': specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.17) + version: 19.2.4(@types/react@19.2.17) '@vitejs/plugin-react': specifier: ^5.2.0 version: 5.2.0(vite@7.3.6(@types/node@22.20.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.5)) @@ -1399,6 +1405,9 @@ packages: '@types/d3-ease@3.0.2': resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + '@types/d3-interpolate@3.0.4': resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} @@ -1423,8 +1432,8 @@ packages: '@types/node@22.20.0': resolution: {integrity: sha512-QWlFW2wf3nTjC13/DqRnBpR4ZO36VJH/JVBkA/vcnmbTBNQIlnObqyqZE1tUR7+Ni23Lda8R1BxMfbXRpCUx5g==} - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + '@types/react-dom@19.2.4': + resolution: {integrity: sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==} peerDependencies: '@types/react': ^19.2.0 @@ -1495,10 +1504,18 @@ packages: resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} engines: {node: '>=12'} + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + d3-ease@3.0.1: resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} engines: {node: '>=12'} + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + d3-format@3.1.2: resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} engines: {node: '>=12'} @@ -1511,6 +1528,10 @@ packages: resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} engines: {node: '>=12'} + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + d3-scale@4.0.2: resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} engines: {node: '>=12'} @@ -2350,58 +2371,58 @@ snapshots: '@radix-ui/primitive@1.1.4': {} - '@radix-ui/react-accordion@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-accordion@1.2.15(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 - '@radix-ui/react-collapsible': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collapsible': 1.1.15(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-alert-dialog@1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-alert-dialog@1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dialog': 1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dialog': 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-arrow@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-arrow@1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-aspect-ratio@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-aspect-ratio@1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-avatar@1.2.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-avatar@1.2.1(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -2409,15 +2430,15 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-checkbox@1.3.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-checkbox@1.3.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -2425,35 +2446,35 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-collapsible@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-collapsible@1.1.15(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-collection@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-collection@1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-compose-refs@1.1.3(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -2461,18 +2482,18 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-context-menu@2.3.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-context-menu@2.3.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-menu': 2.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-menu': 2.1.19(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-context@1.1.4(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -2480,18 +2501,18 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-dialog@1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-dialog@1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) aria-hidden: 1.2.6 @@ -2500,7 +2521,7 @@ snapshots: react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-direction@1.1.2(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -2508,33 +2529,33 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-dismissable-layer@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-dismissable-layer@1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-dropdown-menu@2.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-dropdown-menu@2.1.19(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-menu': 2.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-menu': 2.1.19(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-focus-guards@1.1.4(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -2542,33 +2563,33 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-focus-scope@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-focus-scope@1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-hover-card@1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-hover-card@1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-popper': 1.3.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popper': 1.3.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-id@1.1.2(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -2577,31 +2598,31 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-label@2.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-label@2.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-menu@2.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-menu@2.1.19(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 - '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-popper': 1.3.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popper': 1.3.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) aria-hidden: 1.2.6 @@ -2610,61 +2631,61 @@ snapshots: react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-menubar@1.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-menubar@1.1.19(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 - '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-menu': 2.1.19(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-menu': 2.1.19(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-navigation-menu@1.2.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-navigation-menu@1.2.17(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 - '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-popover@1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-popover@1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-popper': 1.3.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popper': 1.3.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) aria-hidden: 1.2.6 @@ -2673,15 +2694,15 @@ snapshots: react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-popper@1.3.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-popper@1.3.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@floating-ui/react-dom': 2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-arrow': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-arrow': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-rect': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -2691,55 +2712,55 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-portal@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-portal@1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-presence@1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-presence@1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-primitive@2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-primitive@2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-progress@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-progress@1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-radio-group@1.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-radio-group@1.4.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -2747,90 +2768,90 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-roving-focus@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-roving-focus@1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 - '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-scroll-area@1.2.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-scroll-area@1.2.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/number': 1.1.2 '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-select@2.3.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-select@2.3.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/number': 1.1.2 '@radix-ui/primitive': 1.1.4 - '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-popper': 1.3.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popper': 1.3.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) aria-hidden: 1.2.6 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-separator@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-separator@1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-slider@1.4.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-slider@1.4.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/number': 1.1.2 '@radix-ui/primitive': 1.1.4 - '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -2839,7 +2860,7 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-slot@1.3.0(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -2848,12 +2869,12 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-switch@1.3.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-switch@1.3.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) @@ -2861,69 +2882,69 @@ snapshots: react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-tabs@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-tabs@1.1.16(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-toggle-group@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-toggle-group@1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-toggle': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-toggle': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-toggle@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-toggle@1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) - '@radix-ui/react-tooltip@1.2.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-tooltip@1.2.11(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: '@radix-ui/primitive': 1.1.4 '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.14(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-popper': 1.3.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popper': 1.3.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.13(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/react-use-callback-ref@1.1.2(@types/react@19.2.17)(react@19.2.7)': dependencies: @@ -2978,14 +2999,14 @@ snapshots: optionalDependencies: '@types/react': 19.2.17 - '@radix-ui/react-visually-hidden@1.2.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + '@radix-ui/react-visually-hidden@1.2.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': dependencies: - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) optionalDependencies: '@types/react': 19.2.17 - '@types/react-dom': 19.2.3(@types/react@19.2.17) + '@types/react-dom': 19.2.4(@types/react@19.2.17) '@radix-ui/rect@1.1.2': {} @@ -3251,6 +3272,8 @@ snapshots: '@types/d3-ease@3.0.2': {} + '@types/d3-force@3.0.10': {} + '@types/d3-interpolate@3.0.4': dependencies: '@types/d3-color': 3.1.3 @@ -3275,7 +3298,7 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/react-dom@19.2.3(@types/react@19.2.17)': + '@types/react-dom@19.2.4(@types/react@19.2.17)': dependencies: '@types/react': 19.2.17 @@ -3332,12 +3355,12 @@ snapshots: clsx@2.1.1: {} - cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + cmdk@1.1.1(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-dialog': 1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dialog': 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.7(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) transitivePeerDependencies: @@ -3356,8 +3379,16 @@ snapshots: d3-color@3.1.0: {} + d3-dispatch@3.0.1: {} + d3-ease@3.0.1: {} + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + d3-format@3.1.2: {} d3-interpolate@3.0.1: @@ -3366,6 +3397,8 @@ snapshots: d3-path@3.1.0: {} + d3-quadtree@3.0.1: {} + d3-scale@4.0.2: dependencies: d3-array: 3.2.4 @@ -3813,9 +3846,9 @@ snapshots: dependencies: react: 19.2.7 - vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + vaul@1.1.2(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: - '@radix-ui/react-dialog': 1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dialog': 1.1.18(@types/react-dom@19.2.4(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) transitivePeerDependencies: diff --git a/src/lib/theme-api.ts b/src/lib/theme-api.ts index 2b3bfc0..e1990b0 100644 --- a/src/lib/theme-api.ts +++ b/src/lib/theme-api.ts @@ -158,3 +158,63 @@ export async function fetchThemeStocks(themeCode: string): Promise { + const baseUrl = getApiBaseUrl(); + const url = `${baseUrl}/api/themes/graph?sort_field=${sortField}&top=${top}`; + + try { + const resp = await fetch(url, { method: "GET", cache: "no-store" }); + if (!resp.ok) return null; + return await resp.json(); + } catch (err) { + console.error("[theme-api] 获取热点穿透图数据失败:", err); + return null; + } +} diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 344dfd2..b99e2fa 100755 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -11,6 +11,7 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as ThemesRouteImport } from './routes/themes' import { Route as SectorsRouteImport } from './routes/sectors' +import { Route as HotMapRouteImport } from './routes/hot-map' import { Route as IndexRouteImport } from './routes/index' import { Route as ThemeCodeRouteImport } from './routes/theme.$code' import { Route as StockCodeRouteImport } from './routes/stock.$code' @@ -26,6 +27,11 @@ const SectorsRoute = SectorsRouteImport.update({ path: '/sectors', getParentRoute: () => rootRouteImport, } as any) +const HotMapRoute = HotMapRouteImport.update({ + id: '/hot-map', + path: '/hot-map', + getParentRoute: () => rootRouteImport, +} as any) const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', @@ -49,6 +55,7 @@ const ShareCodeRoute = ShareCodeRouteImport.update({ export interface FileRoutesByFullPath { '/': typeof IndexRoute + '/hot-map': typeof HotMapRoute '/sectors': typeof SectorsRoute '/themes': typeof ThemesRoute '/share/$code': typeof ShareCodeRoute @@ -57,6 +64,7 @@ export interface FileRoutesByFullPath { } export interface FileRoutesByTo { '/': typeof IndexRoute + '/hot-map': typeof HotMapRoute '/sectors': typeof SectorsRoute '/themes': typeof ThemesRoute '/share/$code': typeof ShareCodeRoute @@ -66,6 +74,7 @@ export interface FileRoutesByTo { export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute + '/hot-map': typeof HotMapRoute '/sectors': typeof SectorsRoute '/themes': typeof ThemesRoute '/share/$code': typeof ShareCodeRoute @@ -76,6 +85,7 @@ export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath fullPaths: | '/' + | '/hot-map' | '/sectors' | '/themes' | '/share/$code' @@ -84,6 +94,7 @@ export interface FileRouteTypes { fileRoutesByTo: FileRoutesByTo to: | '/' + | '/hot-map' | '/sectors' | '/themes' | '/share/$code' @@ -92,6 +103,7 @@ export interface FileRouteTypes { id: | '__root__' | '/' + | '/hot-map' | '/sectors' | '/themes' | '/share/$code' @@ -101,6 +113,7 @@ export interface FileRouteTypes { } export interface RootRouteChildren { IndexRoute: typeof IndexRoute + HotMapRoute: typeof HotMapRoute SectorsRoute: typeof SectorsRoute ThemesRoute: typeof ThemesRoute ShareCodeRoute: typeof ShareCodeRoute @@ -124,6 +137,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof SectorsRouteImport parentRoute: typeof rootRouteImport } + '/hot-map': { + id: '/hot-map' + path: '/hot-map' + fullPath: '/hot-map' + preLoaderRoute: typeof HotMapRouteImport + parentRoute: typeof rootRouteImport + } '/': { id: '/' path: '/' @@ -157,6 +177,7 @@ declare module '@tanstack/react-router' { const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, + HotMapRoute: HotMapRoute, SectorsRoute: SectorsRoute, ThemesRoute: ThemesRoute, ShareCodeRoute: ShareCodeRoute, diff --git a/src/routes/hot-map.tsx b/src/routes/hot-map.tsx new file mode 100644 index 0000000..16b1396 --- /dev/null +++ b/src/routes/hot-map.tsx @@ -0,0 +1,759 @@ +import { createFileRoute, Link, useNavigate } from "@tanstack/react-router"; +import { useEffect, useMemo, useRef, useState } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { + forceSimulation, + forceLink, + forceManyBody, + forceCenter, + forceCollide, + type SimulationNodeDatum, + type SimulationLinkDatum, +} from "d3-force"; +import { fetchThemeGraph, type ThemeGraph, type GraphStock } from "@/lib/theme-api"; +import { getStockBoard } from "@/lib/stock-api"; +import { formatMoney } from "@/lib/utils"; +import { ArrowLeft, RefreshCw, Flame, TrendingUp, Target, Map as MapIcon, Search, List as ListIcon, Share2 } from "lucide-react"; + +export const Route = createFileRoute("/hot-map")({ + component: HotMapPage, +}); + +/* ============================================================ + 排序维度:涨幅榜 / 热度榜 + ============================================================ */ +const MODES: { key: 1 | 4; label: string }[] = [ + { key: 1, label: "涨幅" }, + { key: 4, label: "热度" }, +]; + +/* 图视图股票节点上限:按覆盖题材数降序保留最高穿透度的核心股 */ +const MAX_STOCK_NODES = 800; + +/* 视图切换:关系图 / 核心股列表 */ +type ViewMode = "graph" | "list"; + +function HotMapPage() { + const [mode, setMode] = useState<1 | 4>(1); + const [view, setView] = useState("graph"); + const isCoarse = useMemo( + () => typeof window !== "undefined" && !!window.matchMedia?.("(pointer: coarse)").matches, + [], + ); + + const { data: graph, isLoading, isFetching, isError, refetch } = useQuery({ + queryKey: ["themeGraph", mode], + queryFn: () => fetchThemeGraph(mode, 50), + staleTime: 60_000, + retry: false, + }); + + return ( +
+ {/* ── 顶栏 ── */} +
+
+
+ + + +

热点穿透

+
+
+ {/* 涨幅/热度切换 */} +
+ {MODES.map((m) => ( + + ))} +
+ {/* 图 / 列表切换 */} +
+ + +
+ +
+
+ + {/* 统计条 */} + {graph?.stats && !isLoading && ( +
+ + 题材 {graph.stats.themeCount} + + + 股票 {graph.stats.stockCount} + + + 穿透核心股 {graph.stats.coreCount} + (覆盖≥2个题材) + +
+ )} +
+ + {/* ── 图主体 ── */} +
+ {isLoading ? ( +
+

正在构建关系网络…

+
+ ) : isError || !graph ? ( +
+

数据加载失败

+ +
+ ) : graph.themes.length === 0 || graph.stocks.length === 0 ? ( +
+ 暂无题材数据 +
+ ) : view === "list" ? ( + + ) : ( + <> + + {/* 图例(触屏紧凑横排) */} + + {/* 操作提示 */} +
+ {isCoarse + ? "点击节点查看 · 再点跳转 · 双指缩放 · 拖拽平移" + : "悬停查看 · 滚轮缩放 · 拖拽平移 · 点击跳转"} +
+ + )} +
+
+ ); +} + +/* ============================================================ + 核心股列表:覆盖题材 > 2 的公司,按覆盖数降序 + ============================================================ */ +function CoreStockList({ stocks }: { stocks: GraphStock[] }) { + // 覆盖题材数 > 2(即 ≥3),接口已按 coverCount 降序、同覆盖按涨幅降序 + const core = stocks.filter((s) => s.coverCount > 2); + const groupMax = core.length ? core[0].coverCount : 0; + + return ( +
+
+ {/* 列表说明 */} +

+ 覆盖 3 个及以上题材的核心股,按覆盖题材数降序(共 {core.length} 家) +

+ + {core.length === 0 ? ( +
+ 当前题材榜中暂无覆盖 3 个及以上题材的核心股 +
+ ) : ( + core.map((s) => { + const board = getStockBoard(s.securityCode); + const isPos = (s.f3 ?? 0) >= 0; + return ( + +
+ {/* 首行:覆盖数徽章 + 名称 + 涨幅 */} +
+ = 7 ? "bg-red-700" : s.coverCount >= 5 ? "bg-red-500" : "bg-orange-500" + }`} + > + {s.coverCount} + +

{s.securityName}

+ {board.label && ( + + {board.label} + + )} + {s.securityCode} + + {isPos ? "+" : ""}{(s.f3 ?? 0).toFixed(2)}% + +
+ + {/* 次行:行业 + 现价 + 覆盖比例条 */} +
+ {s.f100 && ( + {s.f100} + )} + {s.f2 != null && 现价 {s.f2.toFixed(2)}} + {s.themeCodes?.length ?? s.coverCount} 个题材 +
+
= 7 ? "bg-red-700" : s.coverCount >= 5 ? "bg-red-500" : "bg-orange-500"}`} + style={{ width: `${(s.coverCount / Math.max(groupMax, 1)) * 100}%` }} + /> +
+
+
+ + ); + }) + )} +
+
+ ); +} + +/* ============================================================ + 力导向图组件 + ============================================================ */ + +interface SimNode extends SimulationNodeDatum { + id: string; + type: "theme" | "stock"; + name: string; + radius: number; + // stock 专属 + coverCount?: number; + f3?: number | null; + f2?: number | null; + f62?: number | null; + f100?: string; + themeCodes?: string[]; + code?: string; +} + +interface SimEdge extends SimulationLinkDatum { + source: string; + target: string; +} + +function HotMapGraph({ graph }: { graph: ThemeGraph }) { + const containerRef = useRef(null); + const [size, setSize] = useState({ w: 800, h: 600 }); + const [view, setView] = useState({ x: 0, y: 0, k: 1 }); + const [hovered, setHovered] = useState(null); + const [selectedId, setSelectedId] = useState(null); + const [, setTick] = useState(0); + const navigate = useNavigate(); + + /* 触屏检测:触屏无 hover,改用「tap 选中 → 底部浮层查看 → 按钮跳转」交互 */ + const isCoarse = useMemo( + () => typeof window !== "undefined" && !!window.matchMedia?.("(pointer: coarse)").matches, + [], + ); + + const dragRef = useRef<{ active: boolean; sx: number; sy: number; px: number; py: number }>({ + active: false, sx: 0, sy: 0, px: 0, py: 0, + }); + const fitOnceRef = useRef(false); // 力收敛后是否已自动 fit + + /* 监听容器尺寸 */ + useEffect(() => { + const el = containerRef.current; + if (!el) return; + const update = () => setSize({ w: el.clientWidth || 800, h: el.clientHeight || 600 }); + update(); + const ro = new ResizeObserver(update); + ro.observe(el); + return () => ro.disconnect(); + }, []); + + /* 节点过滤:按覆盖题材数降序、同覆盖按涨幅降序,取穿透度最高的前 MAX 只 */ + const { nodes, edges, stockById } = useMemo(() => { + if (!graph) return { nodes: [] as SimNode[], edges: [] as SimEdge[], stockById: new Map() }; + const kept = [...graph.stocks] + .sort((a, b) => b.coverCount - a.coverCount || (b.f3 ?? 0) - (a.f3 ?? 0)) + .slice(0, MAX_STOCK_NODES); + const keptCodes = new Set(kept.map((s) => s.securityCode)); + const keptThemes = new Set(graph.themes.map((t) => t.themeCode)); + + const stockNodes: SimNode[] = kept.map((s) => ({ + id: `s:${s.securityCode}`, + type: "stock" as const, + name: s.securityName, + code: s.securityCode, + coverCount: s.coverCount, + f3: s.f3, + f2: s.f2, + f62: s.f62, + f100: s.f100, + themeCodes: s.themeCodes, + radius: Math.min(18, 4 + s.coverCount * 1.3), + })); + const themeNodes: SimNode[] = graph.themes.map((t) => ({ + id: `t:${t.themeCode}`, + type: "theme" as const, + name: t.themeName, + code: t.themeCode, + coverCount: t.stockCount, + radius: 10, + })); + const edgeList: SimEdge[] = graph.edges + .filter((e) => keptCodes.has(e.securityCode) && keptThemes.has(e.themeCode)) + .map((e) => ({ source: `t:${e.themeCode}`, target: `s:${e.securityCode}` })); + + const stockByIdMap = new Map(); + kept.forEach((s) => stockByIdMap.set(`s:${s.securityCode}`, s)); + + return { nodes: [...themeNodes, ...stockNodes], edges: edgeList, stockById: stockByIdMap }; + }, [graph]); + + /* 预计算相邻关系:nodeId -> Set<相邻nodeId> */ + const adjacency = useMemo(() => { + const adj = new Map>(); + nodes.forEach((n) => adj.set(n.id, new Set())); + edges.forEach((e) => { + const s = typeof e.source === "object" ? (e.source as SimNode).id : e.source; + const t = typeof e.target === "object" ? (e.target as SimNode).id : e.target; + adj.get(s)?.add(t); + adj.get(t)?.add(s); + }); + return adj; + }, [nodes, edges]); + + /* 力导向模拟 */ + useEffect(() => { + if (!nodes.length) return; + const sim = forceSimulation(nodes) + .alphaDecay(0.03) + .force( + "link", + forceLink(edges) + .id((d) => d.id) + .distance((d) => { + const s = d.source as unknown as SimNode; + const t = d.target as unknown as SimNode; + return s.type === "theme" && t.coverCount && t.coverCount >= 3 ? 60 : 40; + }) + .strength(0.6), + ) + .force("charge", forceManyBody().strength((d) => (d.type === "theme" ? -650 : -35))) + .force("center", forceCenter(size.w / 2, size.h / 2)) + // 题材节点留出标签高度防文字重叠(标签在节点下方) + .force("collide", forceCollide().radius((d) => + d.type === "theme" ? d.radius + (isCoarse ? 20 : 16) : d.radius + 4, + )); + + sim.on("tick", () => { + setTick((t) => t + 1); + // 收敛后一次性自动 fit:让整图适配视口(缩小后题材标签隐藏,放大显示) + if (!fitOnceRef.current && sim.alpha() < 0.08) { + const xs = nodes.map((n) => n.x ?? 0); + const ys = nodes.map((n) => n.y ?? 0); + const bw = Math.max(...xs) - Math.min(...xs) + 100; + const bh = Math.max(...ys) - Math.min(...ys) + 100; + if (bw > 0 && bh > 0) { + const k = Math.min(1.2, Math.max(0.25, Math.min(size.w / bw, size.h / bh) * 0.92)); + setView({ + k, + x: size.w / 2 - ((Math.min(...xs) + Math.max(...xs)) / 2) * k, + y: size.h / 2 - ((Math.min(...ys) + Math.max(...ys)) / 2) * k, + }); + fitOnceRef.current = true; + } + } + }); + + return () => { + sim.stop(); + fitOnceRef.current = false; + }; + }, [nodes, edges, size.w, size.h, isCoarse]); + + /* 激活节点:悬停(桌面)或选中(触屏) → 驱动高亮 */ + const activeId = hovered ?? selectedId; + const hoverNeighbors = useMemo(() => { + if (!activeId) return null; + const set = new Set(); + const direct = adjacency.get(activeId); + direct?.forEach((id) => set.add(id)); + // 二级邻居:让题材的邻接股票再扩散一层 + direct?.forEach((id) => adjacency.get(id)?.forEach((nid) => set.add(nid))); + set.add(activeId); + return set; + }, [activeId, adjacency]); + + const activeNode = activeId ? nodes.find((n) => n.id === activeId) : null; + + /* 事件:滚轮缩放 / 拖拽平移 */ + const handleWheel = (e: React.WheelEvent) => { + e.preventDefault(); + const rect = (e.currentTarget as SVGSVGElement).getBoundingClientRect(); + const px = e.clientX - rect.left; + const py = e.clientY - rect.top; + setView((v) => { + const k = Math.min(4, Math.max(0.3, v.k * (e.deltaY < 0 ? 1.12 : 0.89))); + const kRatio = k / v.k; + return { k, x: px - (px - v.x) * kRatio, y: py - (py - v.y) * kRatio }; + }); + }; + + const onPointerDown = (e: React.PointerEvent) => { + if ((e.target as Element).closest("[data-node]")) return; // 点击节点不触发平移 + if (isCoarse) setSelectedId(null); // 触屏点击空白取消选中 + dragRef.current = { active: true, sx: view.x, sy: view.y, px: e.clientX, py: e.clientY }; + (e.currentTarget as SVGSVGElement).setPointerCapture(e.pointerId); + }; + const onPointerMove = (e: React.PointerEvent) => { + const d = dragRef.current; + if (!d.active) return; + setView((v) => ({ ...v, x: d.sx + (e.clientX - d.px), y: d.sy + (e.clientY - d.py) })); + }; + const onPointerUp = () => { dragRef.current.active = false; }; + + /* 节点点击:触屏第一次 tap 选中查看,再 tap 同一节点跳转;桌面直接跳转 */ + const navigateToNode = (node: SimNode) => { + if (node.type === "stock" && node.code) navigate({ to: "/stock/$code", params: { code: node.code } }); + else if (node.type === "theme" && node.code) navigate({ to: "/theme/$code", params: { code: node.code } }); + }; + const handleNodeClick = (node: SimNode) => { + if (isCoarse) { + if (selectedId === node.id) navigateToNode(node); + else setSelectedId(node.id); + } else { + navigateToNode(node); + } + }; + + return ( +
+ + + {/* 边 */} + {edges.map((e, i) => { + const s = typeof e.source === "object" ? (e.source as SimNode) : null; + const t = typeof e.target === "object" ? (e.target as SimNode) : null; + if (!s || !t) return null; + const dim = hoverNeighbors ? (!hoverNeighbors.has(s.id) || !hoverNeighbors.has(t.id)) : false; + return ( + + ); + })} + + {/* 股票节点 */} + {nodes.filter((n) => n.type === "stock").map((n) => { + const dim = hoverNeighbors ? !hoverNeighbors.has(n.id) : false; + const isHover = hovered === n.id; + const isActive = isHover || selectedId === n.id; + const cover = n.coverCount ?? 1; + const fill = cover >= 7 ? "#dc2626" : cover >= 5 ? "#ef4444" : "#f97316"; + const board = getStockBoard(n.code ?? ""); + return ( + setHovered(n.id)} + onMouseLeave={() => setHovered(null)} + onClick={() => handleNodeClick(n)} + > + = 2 ? "#f59e0b" : "#94a3b8"} + strokeWidth={cover >= 2 ? (cover >= 4 ? 2 : 1.5) : 0.5} + /> + = 2 ? 0.9 : 0.55} + /> + {isActive && ( + <> + = 2 ? "#f59e0b" : "#94a3b8"} strokeWidth={1} /> + + {n.name} + + {board.label && ( + + {board.label} + + )} + + )} + + ); + })} + + {/* 题材节点 */} + {nodes.filter((n) => n.type === "theme").map((n) => { + const dim = hoverNeighbors ? !hoverNeighbors.has(n.id) : false; + const isActive = hovered === n.id || selectedId === n.id; + // 标签阈值:放大后显示(避免窄屏 30 个标签重叠),选中节点始终显示 + const showLabel = isActive || view.k >= 0.95; + // 触屏标签更小且截断,减少窄屏文字重叠 + const label = isCoarse ? (n.name.length > 5 ? n.name.slice(0, 5) + "…" : n.name) : n.name; + return ( + setHovered(n.id)} + onMouseLeave={() => setHovered(null)} + onClick={() => handleNodeClick(n)} + > + + {showLabel && ( + + {label} + + )} + + ); + })} + + + + {/* 信息卡:桌面 hover 左上浮层 / 触屏选中底部浮层 */} + {isCoarse ? ( + activeNode && ( + setSelectedId(null)} + onGo={() => navigateToNode(activeNode)} + /> + ) + ) : ( + activeNode && + )} +
+ ); +} + +/* ============================================================ + 信息卡 + ============================================================ */ +function InfoCard({ node, stockById }: { node: SimNode; stockById: Map }) { + const stock = stockById.get(node.id); + const isPos = (node.f3 ?? 0) >= 0; + return ( +
+ {node.type === "stock" ? ( + <> +

+ {node.name} + {node.code} +

+
+ + {isPos ? "+" : ""}{node.f3?.toFixed(2)}% + + {node.f2 != null && 现价 {node.f2.toFixed(2)}} +
+

+ 覆盖 {node.coverCount} 个题材 + {node.coverCount! >= 2 && · 穿透核心} +

+ {node.f62 != null && ( +

主力 {formatMoney(node.f62)}

+ )} + {node.f100 &&

行业:{node.f100}

} + {stock?.themeCodes?.length ? ( +

+ 所属:{stock.themeCodes.length > 3 ? stock.themeCodes.slice(0, 3).join("、") + ` 等${stock.themeCodes.length}个` : stock.themeCodes.join("、")} +

+ ) : null} + + ) : ( + <> +

{node.name}

+

代码 {node.code} · {node.coverCount} 只股票

+ + )} +
+ ); +} + +/* ============================================================ + 底部浮层信息卡(触屏选中节点时展示) + ============================================================ */ +function BottomSheet({ + node, + stockById, + onClose, + onGo, +}: { + node: SimNode; + stockById: Map; + onClose: () => void; + onGo: () => void; +}) { + const stock = stockById.get(node.id); + const isPos = (node.f3 ?? 0) >= 0; + return ( +
+ {/* 顶部拖动条 */} +
+
+
+ {node.type === "stock" ? ( + <> +

+ {node.name} + {node.code} +

+
+ + {isPos ? "+" : ""}{node.f3?.toFixed(2)}% + + {node.f2 != null && 现价 {node.f2.toFixed(2)}} + {node.f62 != null && 主力 {formatMoney(node.f62)}} +
+

+ 覆盖 {node.coverCount} 个题材 + {node.coverCount! >= 2 && ( + · 穿透核心股 + )} + {node.f100 && · {node.f100}} +

+ {stock?.themeCodes?.length ? ( +

+ 所属:{stock.themeCodes.length > 4 ? stock.themeCodes.slice(0, 4).join("、") + ` 等${stock.themeCodes.length}个题材` : stock.themeCodes.join("、")} +

+ ) : null} + + ) : ( + <> +

{node.name}

+

+ 代码 {node.code} · 覆盖 {node.coverCount} 只股票 +

+ + )} +
+ +
+ + {/* 跳转按钮 */} + +
+ ); +} + +/* ============================================================ + 图例(compact:触屏横向紧凑,避免挤占图区) + ============================================================ */ +function Legend({ maxCover, compact }: { maxCover: number; compact: boolean }) { + const high = maxCover >= 5 ? 5 : 4; + if (compact) { + return ( +
+ + + 3–4 个 + + + + ≥5 核心 + + + + 题材 + +
+ ); + } + return ( +
+

图例

+
+
+ + 覆盖 3–4 个题材 +
+
+ + 覆盖 ≥{high} 个题材(核心股) +
+
+
+ + 题材节点 +
+
+ ); +} diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 25d9ea9..8d9072e 100755 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -10,7 +10,7 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; -import { Search, Plus, Share2, Trash2, TrendingUp, Loader2, Flame } from "lucide-react"; +import { Search, Plus, Share2, Trash2, TrendingUp, Loader2, Flame, Network } from "lucide-react"; import { toast } from "sonner"; export const Route = createFileRoute("/")({ @@ -224,6 +224,12 @@ function Index() { 题材热点 + + +
diff --git a/src/routes/themes.tsx b/src/routes/themes.tsx index f9d0d5e..3df85e4 100644 --- a/src/routes/themes.tsx +++ b/src/routes/themes.tsx @@ -13,6 +13,7 @@ import { TrendingUp, TrendingDown, Flame, + Network, } from "lucide-react"; export const Route = createFileRoute("/themes")({ @@ -62,13 +63,22 @@ function ThemesPage() {

题材热点

- +
+ + + 热点穿透 + + +