diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..2cb64fee --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,40 @@ +# Dory - Claude Code Guidelines + +## Project Structure + +- Monorepo managed by Yarn 4 (Berry) workspaces +- `apps/web` — Next.js web app (main product) +- `apps/admin` — Next.js admin panel +- `apps/electron` — Electron desktop app +- `packages/auth-core` — Shared auth package + +## Package Manager + +- **Yarn 4** — use `yarn` commands, NOT `npm` or `pnpm` +- `yarn workspace ` to run workspace-specific commands +- `yarn install` to install dependencies +- `yarn workspace web typecheck` to check types + +## shadcn/ui + +- Components live in `apps/web/registry/new-york-v4/ui/` +- Chart demos live in `apps/web/registry/new-york-v4/charts/` +- **To add/update components**: `yarn dlx shadcn@latest add --overwrite` +- **To update multiple**: `yarn dlx shadcn@latest add comp1 comp2 comp3 --overwrite` +- shadcn CLI may pin dependency versions (remove `^`) or change versions — review `package.json` after running +- shadcn CLI installs to default path; if components are in a custom directory, you may need to move files after + +## Dependency Upgrades + +- Use `npx npm-check-updates --workspaces` to check for outdated dependencies across all workspaces +- Use `yarn npm audit` to check for known vulnerabilities +- For TypeScript major upgrades: run `npx @andrewbranch/ts5to6 --fixBaseUrl ` and `--fixRootDir ` to verify config compatibility +- When upgrading packages that have shadcn wrappers (recharts, react-day-picker, react-resizable-panels), update via `yarn dlx shadcn@latest add --overwrite` to get compatible wrapper code +- Always run `yarn workspace web typecheck` after upgrades to catch breaking changes +- Prefer `^` prefix for dependency versions in package.json + +## Code Style + +- All git commits, PR titles, and branch names must be in **English** +- TypeScript strict mode is enabled across all workspaces +- ESLint with flat config (`eslint.config.mjs`) diff --git a/apps/admin/package.json b/apps/admin/package.json index e3af732b..94e7e2dc 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -12,18 +12,18 @@ }, "dependencies": { "@dory/auth-core": "0.1.0", - "next": "^16.1.7", - "next-intl": "^4.0.2", - "react": "^19.2.1", - "react-dom": "^19.2.1" + "next": "^16.2.2", + "next-intl": "^4.9.0", + "react": "^19.2.4", + "react-dom": "^19.2.4" }, "devDependencies": { "@eslint/eslintrc": "^3", - "@types/node": "^24.3.1", + "@types/node": "^25.5.0", "@types/react": "^19", "@types/react-dom": "^19", - "eslint": "^9", - "eslint-config-next": "15.5.3", - "typescript": "^5.9.2" + "eslint": "^10.1.0", + "eslint-config-next": "^16.2.2", + "typescript": "^6.0.2" } } diff --git a/apps/electron/package.json b/apps/electron/package.json index b267bace..73ba9b17 100644 --- a/apps/electron/package.json +++ b/apps/electron/package.json @@ -19,16 +19,16 @@ "electron:build:apple:unsigned": "yarn run electron:standalone && yarn run compile && CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --config electron-builder.mjs --mac --dir" }, "devDependencies": { - "@types/node": "^24.3.1", - "electron": "39.8.4", - "electron-builder": "^25.1.8", + "@types/node": "^25.5.0", + "electron": "^41.1.1", + "electron-builder": "^26.8.1", "electron-notarize": "^1.2.2", - "typescript": "^5.9.3" + "typescript": "^6.0.2" }, "dependencies": { - "dotenv": "^17.2.3", + "dotenv": "^17.4.0", "electron-log": "^5.4.3", - "electron-store": "^9.0.0", - "electron-updater": "^6.6.2" + "electron-store": "^11.0.2", + "electron-updater": "^6.8.3" } } diff --git a/apps/web/app/(app)/[organization]/[connectionId]/explorer/components/explorer-layout.tsx b/apps/web/app/(app)/[organization]/[connectionId]/explorer/components/explorer-layout.tsx index 5b1119fb..b1140474 100644 --- a/apps/web/app/(app)/[organization]/[connectionId]/explorer/components/explorer-layout.tsx +++ b/apps/web/app/(app)/[organization]/[connectionId]/explorer/components/explorer-layout.tsx @@ -3,7 +3,7 @@ import { useCallback, useEffect, useMemo, type ReactNode } from 'react'; import { useAtom, useAtomValue } from 'jotai'; import { useParams, useRouter } from 'next/navigation'; -import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; +import { Panel, Group, Separator } from 'react-resizable-panels'; import { buildExplorerDatabasePath, buildExplorerListPath, buildExplorerObjectPath, buildExplorerSchemaPath } from '@/lib/explorer/build-path'; import { resolveExplorerRoute } from '@/lib/explorer/routing'; @@ -139,8 +139,8 @@ export function ExplorerLayout({ defaultLayout = [25, 85], children }: ExplorerL return (
- - + +
- + - +
{children}
- +
); } diff --git a/apps/web/app/(app)/[organization]/[connectionId]/explorer/hooks/use-layout.tsx b/apps/web/app/(app)/[organization]/[connectionId]/explorer/hooks/use-layout.tsx index fa259d33..837bc898 100644 --- a/apps/web/app/(app)/[organization]/[connectionId]/explorer/hooks/use-layout.tsx +++ b/apps/web/app/(app)/[organization]/[connectionId]/explorer/hooks/use-layout.tsx @@ -1,6 +1,7 @@ 'use client'; import { useCallback } from 'react'; +import type { Layout } from 'react-resizable-panels'; const HORIZONTAL_LAYOUT_COOKIE = 'data-explorer-panels:layout'; const DEFAULT_HORIZONTAL_LAYOUT = [33, 67] as const; @@ -8,13 +9,14 @@ const DEFAULT_HORIZONTAL_LAYOUT = [33, 67] as const; export function useDataExplorerLayout(defaultLayout: number[] | undefined) { const normalizedLayout = defaultLayout ?? DEFAULT_HORIZONTAL_LAYOUT; - const onLayout = useCallback((sizes: number[]) => { + const onLayout = useCallback((layout: Layout) => { + const sizes = [layout['sidebar'] ?? normalizedLayout[0], layout['content'] ?? normalizedLayout[1]]; try { document.cookie = `${HORIZONTAL_LAYOUT_COOKIE}=${JSON.stringify(sizes)}; path=/; max-age=31536000`; } catch { // ignore cookie failures } - }, []); + }, [normalizedLayout]); return { normalizedLayout, diff --git a/apps/web/app/(app)/[organization]/[connectionId]/sql-console/client.tsx b/apps/web/app/(app)/[organization]/[connectionId]/sql-console/client.tsx index 5233aaf8..f7205b7c 100644 --- a/apps/web/app/(app)/[organization]/[connectionId]/sql-console/client.tsx +++ b/apps/web/app/(app)/[organization]/[connectionId]/sql-console/client.tsx @@ -2,7 +2,7 @@ import React, { Activity, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useAtom, useAtomValue } from 'jotai'; -import { PanelGroup, Panel, PanelResizeHandle } from 'react-resizable-panels'; +import { Group, Panel, Separator as PanelSeparator, type Layout } from 'react-resizable-panels'; import { Sparkles } from 'lucide-react'; import { toast } from 'sonner'; @@ -195,7 +195,8 @@ export default function SQLConsoleClient({ } }, [chatWidth, normalizedChatWidth, setChatWidth]); - const handleLayoutChange = (next: number[]) => { + const handleLayoutChange = (layout: Layout) => { + const next = [layout['left-panel'] ?? horizontalLayout[0], layout['middle-panel'] ?? horizontalLayout[1]]; onLayoutFromHook?.(next); }; @@ -293,12 +294,12 @@ export default function SQLConsoleClient({ return (
- + {/* Left */}
@@ -325,10 +326,10 @@ export default function SQLConsoleClient({
- + {/* Middle */} - +
{isLoading || tabs.length === 0 ? ( @@ -395,7 +396,7 @@ export default function SQLConsoleClient({ )}
-
+
diff --git a/apps/web/app/(app)/[organization]/[connectionId]/sql-console/components/copilot-modes/sql-mode.tsx b/apps/web/app/(app)/[organization]/[connectionId]/sql-console/components/copilot-modes/sql-mode.tsx index 9c29dd54..4dc51932 100644 --- a/apps/web/app/(app)/[organization]/[connectionId]/sql-console/components/copilot-modes/sql-mode.tsx +++ b/apps/web/app/(app)/[organization]/[connectionId]/sql-console/components/copilot-modes/sql-mode.tsx @@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useAtom, useAtomValue } from 'jotai'; -import { PanelGroup, Panel, PanelResizeHandle } from 'react-resizable-panels'; +import { Group, Panel, Separator, type Layout } from 'react-resizable-panels'; import { Check, ChevronDown, Loader2, Play, Save, Square } from 'lucide-react'; import { usePathname, useSearchParams } from 'next/navigation'; @@ -153,16 +153,16 @@ export function SqlMode({ return (
- { - const [, copilotSize] = sizes; - if (copilotSize > 5) setChatWidth(copilotSize); + onLayoutChange={(layout: Layout) => { + const copilotSize = layout['copilot-panel']; + if (copilotSize !== undefined && copilotSize > 5) setChatWidth(copilotSize); }} > - +
@@ -214,31 +214,31 @@ export function SqlMode({ )}
- - + +
- + - +
-
+
- + {showChatbot ? (
@@ -255,7 +255,7 @@ export function SqlMode({
) : null}
- +
diff --git a/apps/web/app/(app)/[organization]/[connectionId]/sql-console/components/copilot-modes/table-mode.tsx b/apps/web/app/(app)/[organization]/[connectionId]/sql-console/components/copilot-modes/table-mode.tsx index 6afb109c..61ab9798 100644 --- a/apps/web/app/(app)/[organization]/[connectionId]/sql-console/components/copilot-modes/table-mode.tsx +++ b/apps/web/app/(app)/[organization]/[connectionId]/sql-console/components/copilot-modes/table-mode.tsx @@ -1,7 +1,7 @@ 'use client'; import React from 'react'; -import { PanelGroup, Panel, PanelResizeHandle } from 'react-resizable-panels'; +import { Group, Panel, Separator, type Layout } from 'react-resizable-panels'; import TableBrowser from '../../../../components/table-browser/table-browser'; import CopilotPanel from '../copilot-panel'; @@ -25,16 +25,16 @@ export function TableMode({ return (
- { - const [, copilotSize] = sizes; - if (copilotSize > 5) setChatWidth(copilotSize); + onLayoutChange={(layout: Layout) => { + const copilotSize = layout['copilot-panel']; + if (copilotSize !== undefined && copilotSize > 5) setChatWidth(copilotSize); }} > - +
@@ -42,17 +42,17 @@ export function TableMode({
- {showChatbot ? ( @@ -69,7 +69,7 @@ export function TableMode({
) : null}
-
+
); } diff --git a/apps/web/app/(app)/[organization]/[connectionId]/sql-console/components/result-table/components/charts/chart-canvas.tsx b/apps/web/app/(app)/[organization]/[connectionId]/sql-console/components/result-table/components/charts/chart-canvas.tsx index 04bb5c2f..1e5a8a1d 100644 --- a/apps/web/app/(app)/[organization]/[connectionId]/sql-console/components/result-table/components/charts/chart-canvas.tsx +++ b/apps/web/app/(app)/[organization]/[connectionId]/sql-console/components/result-table/components/charts/chart-canvas.tsx @@ -431,7 +431,7 @@ export function ChartCanvas(props: { className="cursor-pointer" onClick={(data, _index, event) => handleDatumClick( - ((data as { payload?: Record } | undefined)?.payload ?? (data as Record | undefined)), + ((data as unknown as { payload?: Record } | undefined)?.payload ?? (data as unknown as Record | undefined)), ALL_SERIES_KEY, 'Value', Boolean((event as React.MouseEvent | undefined)?.shiftKey), @@ -493,7 +493,7 @@ export function ChartCanvas(props: { ); } -function ScatterTooltipContent(props: React.ComponentProps & { yAxisLabel: string }) { +function ScatterTooltipContent(props: React.ComponentProps & { yAxisLabel: string; active?: boolean; payload?: Array<{ payload?: Record }> }) { const { active, payload, yAxisLabel } = props; if (!active || !payload?.length) { return null; @@ -518,7 +518,7 @@ function ScatterTooltipContent(props: React.ComponentProps & { filterEnabled?: boolean; chartConfig: ChartConfig; xAxisLabel: string; yAxisLabel: string }) { +function ChartFilterTooltipContent(props: React.ComponentProps & { filterEnabled?: boolean; chartConfig: ChartConfig; xAxisLabel: string; yAxisLabel: string; active?: boolean; payload?: Array> }) { const { filterEnabled, chartConfig, xAxisLabel, yAxisLabel } = props; if (!props.active || !props.payload?.length) { return null; diff --git a/apps/web/lib/registry.ts b/apps/web/lib/registry.ts index 27db61ec..961dd89c 100644 --- a/apps/web/lib/registry.ts +++ b/apps/web/lib/registry.ts @@ -1,5 +1,5 @@ import { Index } from "@/__registry__" -import { registryItemSchema } from "shadcn/registry" +import { registryItemSchema } from "shadcn/schema" const memoizedIndex: typeof Index = Object.fromEntries( Object.entries(Index).map(([style, items]) => [style, { ...items }]) diff --git a/apps/web/package.json b/apps/web/package.json index 9d5b4716..8321af44 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -39,16 +39,16 @@ "registry:build": "tsx --tsconfig ./tsconfig.scripts.json ./scripts/build-registry.mts && prettier --log-level silent --write \"registry/**/*.{ts,tsx,json,mdx}\" --cache" }, "dependencies": { - "@ai-sdk/anthropic": "^3.0.13", - "@ai-sdk/google": "^3.0.8", - "@ai-sdk/openai": "^3.0.21", - "@ai-sdk/openai-compatible": "^2.0.0", - "@ai-sdk/react": "^3.0.61", - "@ai-sdk/xai": "^3.0.23", - "@better-auth/infra": "^0.1.12", - "@better-auth/sso": "^1.5.5", - "@better-auth/stripe": "1.5.5", - "@clickhouse/client": "^1.12.0", + "@ai-sdk/anthropic": "^3.0.66", + "@ai-sdk/google": "^3.0.57", + "@ai-sdk/openai": "^3.0.50", + "@ai-sdk/openai-compatible": "^2.0.38", + "@ai-sdk/react": "^3.0.147", + "@ai-sdk/xai": "^3.0.77", + "@better-auth/infra": "^0.1.13", + "@better-auth/sso": "^1.5.6", + "@better-auth/stripe": "1.5.6", + "@clickhouse/client": "^1.18.2", "@dnd-kit/core": "^6.3.1", "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", @@ -57,161 +57,161 @@ "@faker-js/faker": "^10.4.0", "@hookform/resolvers": "^5.2.2", "@monaco-editor/react": "^4.7.0", - "@paper-design/shaders-react": "^0.0.71", - "@radix-ui/react-accessible-icon": "^1.1.1", + "@paper-design/shaders-react": "^0.0.72", + "@radix-ui/react-accessible-icon": "^1.1.8", "@radix-ui/react-accordion": "^1.2.12", - "@radix-ui/react-alert-dialog": "^1.1.5", - "@radix-ui/react-aspect-ratio": "^1.1.1", + "@radix-ui/react-alert-dialog": "^1.1.15", + "@radix-ui/react-aspect-ratio": "^1.1.8", "@radix-ui/react-avatar": "^1.1.11", - "@radix-ui/react-checkbox": "^1.1.3", + "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-collapsible": "^1.1.12", - "@radix-ui/react-context-menu": "^2.2.5", + "@radix-ui/react-context-menu": "^2.2.16", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-hover-card": "^1.1.15", "@radix-ui/react-icons": "^1.3.2", - "@radix-ui/react-label": "^2.1.1", - "@radix-ui/react-menubar": "^1.1.5", - "@radix-ui/react-navigation-menu": "^1.2.4", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-menubar": "^1.1.16", + "@radix-ui/react-navigation-menu": "^1.2.14", "@radix-ui/react-popover": "^1.1.15", - "@radix-ui/react-portal": "^1.1.3", + "@radix-ui/react-portal": "^1.1.10", "@radix-ui/react-progress": "^1.1.8", - "@radix-ui/react-radio-group": "^1.2.2", + "@radix-ui/react-radio-group": "^1.3.8", "@radix-ui/react-scroll-area": "^1.2.10", "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-separator": "^1.1.8", - "@radix-ui/react-slider": "^1.2.2", + "@radix-ui/react-slider": "^1.3.6", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-switch": "^1.2.6", "@radix-ui/react-tabs": "^1.1.13", - "@radix-ui/react-toast": "^1.2.5", - "@radix-ui/react-toggle": "^1.1.1", - "@radix-ui/react-toggle-group": "^1.1.1", + "@radix-ui/react-toast": "^1.2.15", + "@radix-ui/react-toggle": "^1.1.10", + "@radix-ui/react-toggle-group": "^1.1.11", "@radix-ui/react-tooltip": "^1.2.8", "@radix-ui/react-use-controllable-state": "^1.2.2", - "@radix-ui/react-visually-hidden": "^1.1.2", - "@react-email/render": "^1.2.3", + "@radix-ui/react-visually-hidden": "^1.2.4", + "@react-email/render": "^2.0.5", "@react-spring/three": "^10.0.3", "@react-three/fiber": "^9.5.0", - "@rive-app/react-webgl2": "^4.26.1", + "@rive-app/react-webgl2": "^4.27.3", "@shadergradient/react": "^2.4.20", - "@streamdown/cjk": "^1.0.1", - "@streamdown/code": "^1.0.1", - "@streamdown/math": "^1.0.1", - "@streamdown/mermaid": "^1.0.1", - "@tabler/icons-react": "^3.31.0", - "@tanstack/react-query": "^5.83.0", + "@streamdown/cjk": "^1.0.3", + "@streamdown/code": "^1.1.1", + "@streamdown/math": "^1.0.2", + "@streamdown/mermaid": "^1.0.2", + "@tabler/icons-react": "^3.41.1", + "@tanstack/react-query": "^5.96.1", "@tanstack/react-table": "^8.21.3", - "@tanstack/react-virtual": "^3.13.12", + "@tanstack/react-virtual": "^3.13.23", "@types/better-sqlite3": "^7.6.13", "@types/lodash-es": "^4.17.12", - "@types/mssql": "^9.1.7", + "@types/mssql": "^9.1.11", "@types/pako": "^2.0.4", - "@types/pg": "^8.15.4", + "@types/pg": "^8.20.0", "@types/react-syntax-highlighter": "^15.5.13", - "@types/react-virtualized": "^9.22.2", - "@vercel/analytics": "^1.2.2", - "@xyflow/react": "^12.10.0", + "@types/react-virtualized": "^9.22.3", + "@vercel/analytics": "^2.0.1", + "@xyflow/react": "^12.10.2", "add": "^2.0.6", - "ai": "^6.0.59", - "ai-gateway-provider": "^3.1.1", + "ai": "^6.0.145", + "ai-gateway-provider": "^3.1.3", "ansi-to-react": "^6.2.6", - "better-auth": "^1.5.5", - "better-sqlite3": "^12.5.0", + "better-auth": "^1.5.6", + "better-sqlite3": "^12.8.0", "boring-avatars": "^2.0.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", - "dayjs": "^1.11.18", - "debounce": "^2.2.0", - "dotenv": "^17.2.3", - "drizzle-orm": "^0.44.5", + "dayjs": "^1.11.20", + "debounce": "^3.0.0", + "dotenv": "^17.4.0", + "drizzle-orm": "^0.45.2", "drizzle-zod": "^0.8.3", - "dt-sql-parser": "^4.4.0", - "embla-carousel-autoplay": "8.5.2", - "embla-carousel-react": "8.5.2", - "fuse.js": "^7.1.0", - "geist": "^1.2.2", + "dt-sql-parser": "^4.4.2", + "embla-carousel-autoplay": "8.6.0", + "embla-carousel-react": "8.6.0", + "fuse.js": "^7.2.0", + "geist": "^1.7.0", "i": "^0.3.7", "input-otp": "^1.4.2", - "jotai": "^2.12.2", + "jotai": "^2.19.0", "lodash": "^4.18.1", "lodash-es": "^4.18.1", - "lucide-react": "0.562.0", - "lucide-static": "^0.556.0", - "media-chrome": "^4.17.2", + "lucide-react": "^1.7.0", + "lucide-static": "^1.7.0", + "media-chrome": "^4.18.3", "monaco-editor": "^0.55.1", - "monaco-editor-webpack-plugin": "^7.1.0", - "motion": "^12.23.26", - "mssql": "^11.0.1", + "monaco-editor-webpack-plugin": "^7.1.1", + "motion": "^12.38.0", + "mssql": "^12.2.1", "mysql2": "^3.20.0", - "nanoid": "^5.1.6", - "next": "16.2.1", - "next-intl": "^4.0.2", + "nanoid": "^5.1.7", + "next": "16.2.2", + "next-intl": "^4.9.0", "next-runtime-env": "^3.3.0", - "next-themes": "^0.4.3", - "npm": "^11.6.0", + "next-themes": "^0.4.6", + "npm": "^11.12.1", "pako": "^2.1.0", - "pg": "^8.16.2", - "pino": "^9.9.5", - "pino-pretty": "^13.1.1", - "postcss": "^8.5.1", - "posthog-js": "^1.360.1", - "posthog-node": "4", + "pg": "^8.20.0", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3", + "postcss": "^8.5.8", + "posthog-js": "^1.364.6", + "posthog-node": "5", "prism-react-renderer": "^2.4.1", "qwen-ai-provider": "^0.1.1", - "radix-ui": "^1.4.2", + "radix-ui": "^1.4.3", "react": "19.2.4", - "react-day-picker": "^8.7.1", + "react-day-picker": "^9.14.0", "react-dom": "19.2.4", - "react-hook-form": "^7.66.1", - "react-resizable-panels": "^3.0.5", - "react-syntax-highlighter": "^15.6.6", + "react-hook-form": "^7.72.0", + "react-resizable-panels": "^4.9.0", + "react-syntax-highlighter": "^16.1.1", "react-virtualized": "^9.22.6", - "react-window": "^2.0.2", - "recharts": "2.15.1", - "resend": "^6.1.0", - "rimraf": "^6.0.1", - "shadcn": "2.3.0", - "shiki": "^3.20.0", - "sonner": "^2.0.0", - "sql-formatter": "^15.6.6", + "react-window": "^2.2.7", + "recharts": "^3.8.1", + "resend": "^6.10.0", + "rimraf": "^6.1.3", + "shadcn": "^4.1.2", + "shiki": "^4.0.2", + "sonner": "^2.0.7", + "sql-formatter": "^15.7.3", "ssh2": "^1.17.0", "ssh2-no-cpu-features": "^2.0.0", - "streamdown": "^2.1.0", - "stripe": "^20", - "swr": "^2.3.3", - "tailwind-merge": "^3.0.1", - "tailwindcss": "^4.0.7", - "three": "^0.182.0", + "streamdown": "^2.5.0", + "stripe": "^22", + "swr": "^2.4.1", + "tailwind-merge": "^3.5.0", + "tailwindcss": "^4.2.2", + "three": "^0.183.2", "tokenlens": "^1.3.1", - "ts-morph": "^22.0.0", + "ts-morph": "^27.0.2", "ts-node": "^10.9.2", - "tsx": "^4.20.5", - "tw-animate-css": "^1.2.4", - "use-stick-to-bottom": "^1.1.1", - "uuid": "^11.1.0", + "tsx": "^4.21.0", + "tw-animate-css": "^1.4.0", + "use-stick-to-bottom": "^1.1.3", + "uuid": "^13.0.0", "vaul": "1.1.2", - "zod": "^4.1.12" + "zod": "^4.3.6" }, "devDependencies": { "@eslint/eslintrc": "^3", - "@ianvs/prettier-plugin-sort-imports": "^3.7.2", - "@opennextjs/cloudflare": "^1.15.1", + "@ianvs/prettier-plugin-sort-imports": "^4.7.1", + "@opennextjs/cloudflare": "^1.18.0", "@tailwindcss/postcss": "^4", - "@types/node": "^24.3.1", + "@types/node": "^25.5.0", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", - "@types/three": "^0.182.0", - "@typescript-eslint/parser": "^5.59.7", + "@types/three": "^0.183.1", + "@typescript-eslint/parser": "^8.58.0", "drizzle-kit": "^0.31.10", - "eslint": "^9", - "eslint-config-next": "16.2.1", - "prettier": "^3.4.2", - "prettier-plugin-tailwindcss": "^0.6.11", - "typescript": "^5.9.2", - "wrangler": "^4.60.0" + "eslint": "^10.1.0", + "eslint-config-next": "16.2.2", + "prettier": "^3.8.1", + "prettier-plugin-tailwindcss": "^0.7.2", + "typescript": "^6.0.2", + "wrangler": "^4.80.0" }, "resolutions": { "@types/react": "19.2.14", diff --git a/apps/web/registry/new-york-v4/charts/chart-bar-active.tsx b/apps/web/registry/new-york-v4/charts/chart-bar-active.tsx index bcc8631e..f76c5812 100644 --- a/apps/web/registry/new-york-v4/charts/chart-bar-active.tsx +++ b/apps/web/registry/new-york-v4/charts/chart-bar-active.tsx @@ -2,6 +2,7 @@ import { TrendingUp } from "lucide-react" import { Bar, BarChart, CartesianGrid, Rectangle, XAxis } from "recharts" +import type { BarShapeProps } from "recharts/types/cartesian/Bar" import { Card, @@ -12,10 +13,10 @@ import { CardTitle, } from "@/registry/new-york-v4/ui/card" import { - ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, + type ChartConfig, } from "@/registry/new-york-v4/ui/chart" export const description = "A bar chart with an active bar" @@ -54,6 +55,8 @@ const chartConfig = { }, } satisfies ChartConfig +const ACTIVE_INDEX = 2 + export function ChartBarActive() { return ( @@ -82,9 +85,8 @@ export function ChartBarActive() { dataKey="visitors" strokeWidth={2} radius={8} - activeIndex={2} - activeBar={({ ...props }) => { - return ( + shape={({ index, ...props }: BarShapeProps) => + index === ACTIVE_INDEX ? ( + ) : ( + ) - }} + } /> @@ -102,7 +106,7 @@ export function ChartBarActive() {
Trending up by 5.2% this month
-
+
Showing total visitors for the last 6 months
diff --git a/apps/web/registry/new-york-v4/charts/chart-bar-label-custom.tsx b/apps/web/registry/new-york-v4/charts/chart-bar-label-custom.tsx index 3c084bf0..bde2b2bf 100644 --- a/apps/web/registry/new-york-v4/charts/chart-bar-label-custom.tsx +++ b/apps/web/registry/new-york-v4/charts/chart-bar-label-custom.tsx @@ -12,10 +12,10 @@ import { CardTitle, } from "@/registry/new-york-v4/ui/card" import { - ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, + type ChartConfig, } from "@/registry/new-york-v4/ui/chart" export const description = "A bar chart with a custom label" @@ -32,7 +32,7 @@ const chartData = [ const chartConfig = { desktop: { label: "Desktop", - color: "var(--chart-1)", + color: "var(--chart-2)", }, mobile: { label: "Mobile", @@ -75,12 +75,7 @@ export function ChartBarLabelCustom() { cursor={false} content={} /> - + Trending up by 5.2% this month
-
+
Showing total visitors for the last 6 months
diff --git a/apps/web/registry/new-york-v4/charts/chart-bar-mixed.tsx b/apps/web/registry/new-york-v4/charts/chart-bar-mixed.tsx index 1e622051..bac07d75 100644 --- a/apps/web/registry/new-york-v4/charts/chart-bar-mixed.tsx +++ b/apps/web/registry/new-york-v4/charts/chart-bar-mixed.tsx @@ -12,10 +12,10 @@ import { CardTitle, } from "@/registry/new-york-v4/ui/card" import { - ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, + type ChartConfig, } from "@/registry/new-york-v4/ui/chart" export const description = "A mixed bar chart" @@ -86,7 +86,7 @@ export function ChartBarMixed() { cursor={false} content={} /> - + @@ -94,7 +94,7 @@ export function ChartBarMixed() {
Trending up by 5.2% this month
-
+
Showing total visitors for the last 6 months
diff --git a/apps/web/registry/new-york-v4/charts/chart-line-dots-custom.tsx b/apps/web/registry/new-york-v4/charts/chart-line-dots-custom.tsx index 9c1b8d58..355f23a1 100644 --- a/apps/web/registry/new-york-v4/charts/chart-line-dots-custom.tsx +++ b/apps/web/registry/new-york-v4/charts/chart-line-dots-custom.tsx @@ -12,10 +12,10 @@ import { CardTitle, } from "@/registry/new-york-v4/ui/card" import { - ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, + type ChartConfig, } from "@/registry/new-york-v4/ui/chart" export const description = "A line chart with custom dots" @@ -75,7 +75,12 @@ export function ChartLineDotsCustom() { stroke="var(--color-desktop)" strokeWidth={2} dot={({ cx, cy, payload }) => { + if (cx == null || cy == null) { + return null + } + const r = 24 + return ( Trending up by 5.2% this month
-
+
Showing total visitors for the last 6 months
diff --git a/apps/web/registry/new-york-v4/charts/chart-line-label-custom.tsx b/apps/web/registry/new-york-v4/charts/chart-line-label-custom.tsx index 6f30ee17..14aaa7f9 100644 --- a/apps/web/registry/new-york-v4/charts/chart-line-label-custom.tsx +++ b/apps/web/registry/new-york-v4/charts/chart-line-label-custom.tsx @@ -12,10 +12,10 @@ import { CardTitle, } from "@/registry/new-york-v4/ui/card" import { - ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, + type ChartConfig, } from "@/registry/new-york-v4/ui/chart" export const description = "A line chart with a custom label" @@ -102,8 +102,8 @@ export function ChartLineLabelCustom() { className="fill-foreground" fontSize={12} dataKey="browser" - formatter={(value: keyof typeof chartConfig) => - chartConfig[value]?.label + formatter={(value) => + chartConfig[value as keyof typeof chartConfig]?.label } /> @@ -114,7 +114,7 @@ export function ChartLineLabelCustom() {
Trending up by 5.2% this month
-
+
Showing total visitors for the last 6 months
diff --git a/apps/web/registry/new-york-v4/charts/chart-pie-donut-active.tsx b/apps/web/registry/new-york-v4/charts/chart-pie-donut-active.tsx index 65a909a3..b2e41b5e 100644 --- a/apps/web/registry/new-york-v4/charts/chart-pie-donut-active.tsx +++ b/apps/web/registry/new-york-v4/charts/chart-pie-donut-active.tsx @@ -2,7 +2,7 @@ import { TrendingUp } from "lucide-react" import { Label, Pie, PieChart, Sector } from "recharts" -import { PieSectorDataItem } from "recharts/types/polar/Pie" +import type { PieSectorShapeProps } from "recharts/types/polar/Pie" import { Card, @@ -13,10 +13,10 @@ import { CardTitle, } from "@/registry/new-york-v4/ui/card" import { - ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, + type ChartConfig, } from "@/registry/new-york-v4/ui/chart" export const description = "A donut chart with an active sector" @@ -55,6 +55,8 @@ const chartConfig = { }, } satisfies ChartConfig +const ACTIVE_INDEX = 0 + export function ChartPieDonutActive() { return ( @@ -78,13 +80,17 @@ export function ChartPieDonutActive() { nameKey="browser" innerRadius={60} strokeWidth={5} - activeIndex={0} - activeShape={({ + shape={({ + index, outerRadius = 0, ...props - }: PieSectorDataItem) => ( - - )} + }: PieSectorShapeProps) => + index === ACTIVE_INDEX ? ( + + ) : ( + + ) + } /> @@ -93,7 +99,7 @@ export function ChartPieDonutActive() {
Trending up by 5.2% this month
-
+
Showing total visitors for the last 6 months
diff --git a/apps/web/registry/new-york-v4/charts/chart-pie-interactive.tsx b/apps/web/registry/new-york-v4/charts/chart-pie-interactive.tsx index 06dd2579..dfe17b68 100644 --- a/apps/web/registry/new-york-v4/charts/chart-pie-interactive.tsx +++ b/apps/web/registry/new-york-v4/charts/chart-pie-interactive.tsx @@ -2,7 +2,10 @@ import * as React from "react" import { Label, Pie, PieChart, Sector } from "recharts" -import { PieSectorDataItem } from "recharts/types/polar/Pie" +import type { + PieSectorDataItem, + PieSectorShapeProps, +} from "recharts/types/polar/Pie" import { Card, @@ -12,11 +15,11 @@ import { CardTitle, } from "@/registry/new-york-v4/ui/card" import { - ChartConfig, ChartContainer, ChartStyle, ChartTooltip, ChartTooltipContent, + type ChartConfig, } from "@/registry/new-york-v4/ui/chart" import { Select, @@ -78,6 +81,26 @@ export function ChartPieInteractive() { ) const months = React.useMemo(() => desktopData.map((item) => item.month), []) + const renderPieShape = React.useCallback( + ({ index, outerRadius = 0, ...props }: PieSectorShapeProps) => { + if (index === activeIndex) { + return ( + + + + + ) + } + + return + }, + [activeIndex] + ) + return ( @@ -139,20 +162,7 @@ export function ChartPieInteractive() { nameKey="month" innerRadius={60} strokeWidth={5} - activeIndex={activeIndex} - activeShape={({ - outerRadius = 0, - ...props - }: PieSectorDataItem) => ( - - - - - )} + shape={renderPieShape} >