diff --git a/package-lock.json b/package-lock.json index 9a2b3c8a5..d1bdd6735 100644 --- a/package-lock.json +++ b/package-lock.json @@ -76,7 +76,6 @@ "@types/react-katex": "^3.0.4", "@types/react-timeago": "^4.1.7", "@types/turndown": "^5.0.5", - "chart.js": "4.4.4", "eslint": "^8.57.1", "eslint-config-next": "^14.2.13", "prettier": "^3.3.3", @@ -1045,13 +1044,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@kurkle/color": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", - "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==", - "dev": true, - "license": "MIT" - }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", @@ -2973,19 +2965,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chart.js": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.4.tgz", - "integrity": "sha512-emICKGBABnxhMjUjlYRR12PmOXhJ2eJjEHL2/dZlWjxRAZT1D8xplLFq5M0tMQK8ja+wBS/tuVEJB5C6r7VxJA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@kurkle/color": "^0.3.0" - }, - "engines": { - "pnpm": ">=8" - } - }, "node_modules/cheerio": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", diff --git a/package.json b/package.json index a6d2e2e73..142754dad 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,6 @@ "@types/react-katex": "^3.0.4", "@types/react-timeago": "^4.1.7", "@types/turndown": "^5.0.5", - "chart.js": "4.4.4", "eslint": "^8.57.1", "eslint-config-next": "^14.2.13", "prettier": "^3.3.3", diff --git a/src/modules/blocks/code/code-renderers/RenderCodeChartJS.tsx b/src/modules/blocks/code/code-renderers/RenderCodeChartJS.tsx index 496183736..08e40ab66 100644 --- a/src/modules/blocks/code/code-renderers/RenderCodeChartJS.tsx +++ b/src/modules/blocks/code/code-renderers/RenderCodeChartJS.tsx @@ -6,7 +6,7 @@ import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome'; import { useAgiFixupCode } from '~/modules/aifn/agicodefixup/useAgiFixupCode'; -import { ChartConstructorType, fixupChartJSObject, useDynamicChartJS } from './useDynamicChartJS'; +import { ChartConfiguration, ChartInstanceType, fixupChartJSObject, useDynamicChartJS } from './useDynamicChartJS'; const chartContainerSx: SxProps = { @@ -34,7 +34,7 @@ export function RenderCodeChartJS(props: { const [renderError, setRenderError] = React.useState(null); const [fixupError, setFixupError] = React.useState(null); const canvasRef = React.useRef(null); - const chartInstanceRef = React.useRef(null); + const chartInstanceRef = React.useRef(null); // external state const { chartJS, loadingError, isLoading: isLibraryLoading } = useDynamicChartJS(); @@ -43,7 +43,7 @@ export function RenderCodeChartJS(props: { // immediate parsing (note, this could be done with useEffect and state, but we save a render cycle) const parseResult = React.useMemo(() => { try { - const config = JSON.parse(props.chartJSCode) as ChartConstructorType['config']; + const config = JSON.parse(props.chartJSCode) as ChartConfiguration; fixupChartJSObject(config); return { chartConfig: config, parseError: null }; } catch (error: any) { diff --git a/src/modules/blocks/code/code-renderers/useDynamicChartJS.ts b/src/modules/blocks/code/code-renderers/useDynamicChartJS.ts index 38fba8b56..5d932a675 100644 --- a/src/modules/blocks/code/code-renderers/useDynamicChartJS.ts +++ b/src/modules/blocks/code/code-renderers/useDynamicChartJS.ts @@ -7,9 +7,7 @@ import * as React from 'react'; import { create } from 'zustand'; -import type { Chart as ChartConstructorType } from 'chart.js/auto'; -import { devDependencies } from '../../../../../package.json'; import { themeFontFamilyCss } from '~/common/app.theme'; @@ -18,18 +16,50 @@ const CHARTJS_VERSION = '4.4.4'; const CHARTJS_CDN_URL = `https://cdn.jsdelivr.net/npm/chart.js@${CHARTJS_VERSION}/dist/chart.umd.js`; const CHARTJS_SCRIPT_ID = 'chartjs-cdn'; -export type { ChartConstructorType }; + +// Minimal type definitions for Chart.js - as of 4.4.4 + +interface ChartConstructorType { + defaults: ChartDefaults; + + new(context: CanvasRenderingContext2D | HTMLCanvasElement, config: ChartConfiguration): ChartInstanceType; +} + +interface ChartDefaults { + font: { + family: string; + size: number; + }; + maintainAspectRatio: boolean; + responsive: boolean; +} + +export interface ChartConfiguration { + type?: string; + data?: any; + options?: { + responsive?: boolean; + maintainAspectRatio?: boolean; + [key: string]: any; + }; + + [key: string]: any; +} + +export interface ChartInstanceType { + destroy(): void; +} // Code manipulation functions -export function fixupChartJSObject(chartConfig: ChartConstructorType['config']): void { - // Remove responsive options - we hadle this ourselves by default +export function fixupChartJSObject(chartConfig: ChartConfiguration): void { + // Remove responsive options - we handle this ourselves by default delete chartConfig?.options?.responsive; delete chartConfig?.options?.maintainAspectRatio; } -function _initializeChartJS(Chart: typeof ChartConstructorType): typeof ChartConstructorType { +function _initializeChartJS(Chart: ChartConstructorType): ChartConstructorType { Chart.defaults.font.family = themeFontFamilyCss; Chart.defaults.font.size = 13; Chart.defaults.maintainAspectRatio = true; // defaults to 1 for polar and so, 2 for bars and more @@ -40,20 +70,20 @@ function _initializeChartJS(Chart: typeof ChartConstructorType): typeof ChartCon // Singleton promise for loading Chart.js -let chartJSPromise: Promise | null = null; - -function loadCDNScript(): Promise { +let chartJSPromise: Promise | null = null; +function loadCDNScript(): Promise { // Resolve immediately if already loaded if ((window as any).Chart) - return Promise.resolve((window as any).Chart); + return Promise.resolve(_initializeChartJS((window as any).Chart)); // If loading has already started, return the existing promise if (chartJSPromise) return chartJSPromise; // Ensure the API definitions from package.json match the CDN loaded version - if (devDependencies['chart.js'] !== CHARTJS_VERSION) - return Promise.reject(new Error(`Chart.js version mismatch: loaded ${CHARTJS_VERSION}, expected ${devDependencies['chart.js']}.`)); + // NOTE: Disabled because we are not using the package.json version anymore, we replaced the API + // if (devDependencies['chart.js'] !== CHARTJS_VERSION) + // return Promise.reject(new Error(`Chart.js version mismatch: loaded ${CHARTJS_VERSION}, expected ${devDependencies['chart.js']}.`)); chartJSPromise = new Promise((resolve, reject) => { @@ -84,7 +114,7 @@ function loadCDNScript(): Promise { interface ChartApiStore { // state - chartJS: typeof ChartConstructorType | null; + chartJS: ChartConstructorType | null; loadingError: string | null; isLoading: boolean;