Conversation
…/line/area support and theme-based color fallback
…pport, and internal config builder
…king, and shared config builder
…ion, and 80%+ coverage
|
There was a problem hiding this comment.
Pull request overview
This PR repurposes the template package into @ciscode/ui-chart-kit, introducing typed Chart.js-based React chart components plus shared chart types and a config builder utility.
Changes:
- Added
BarChart,LineChart, andAreaChartcomponents backed by a sharedbuildChartConfigutility. - Introduced public chart type contracts (
ChartDataPoint,ChartDataset,ChartTheme, etc.) and exported them from the package entrypoint. - Updated package identity/docs and added release metadata (changeset).
Reviewed changes
Copilot reviewed 24 out of 27 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/index.ts | Re-exports the new buildChartConfig utility. |
| src/utils/buildChartConfig.ts | Implements typed Chart.js config/dataset construction. |
| src/utils/buildChartConfig.test.ts | Unit tests for config building across variants and theme options. |
| src/types/index.ts | Public re-export barrel for chart types. |
| src/types/chart.types.ts | Defines public chart data/theme/config types. |
| src/index.ts | Exposes types from the package root. |
| src/components/index.ts | Exports the new chart components from the components barrel. |
| src/components/BarChart/index.ts | Component barrel export for BarChart. |
| src/components/BarChart/BarChart.types.ts | Typed props for BarChart. |
| src/components/BarChart/BarChart.tsx | Bar chart component implementation. |
| src/components/BarChart/BarChart.test.tsx | Component tests for bar chart behavior (stacked/horizontal/etc.). |
| src/components/LineChart/index.ts | Component barrel export for LineChart. |
| src/components/LineChart/LineChart.types.ts | Typed props for LineChart. |
| src/components/LineChart/LineChart.tsx | Line chart component implementation. |
| src/components/LineChart/LineChart.test.tsx | Component tests for line chart behavior (smooth/tension). |
| src/components/AreaChart/index.ts | Component barrel export for AreaChart. |
| src/components/AreaChart/AreaChart.types.ts | Typed props for AreaChart. |
| src/components/AreaChart/AreaChart.tsx | Area chart component implementation (fill/stacking/smooth). |
| src/components/AreaChart/AreaChart.test.tsx | Component tests for area chart behavior (fill/stacked/smooth). |
| src/tests/chart-test-utils.ts | Shared test helpers and fixtures for chart components. |
| README.md | Rewritten documentation for the chart kit API and usage examples. |
| package.json | Renames/versions the package and adds Chart.js dependencies. |
| package-lock.json | Lockfile updated for new dependencies (but root metadata still references old name/version). |
| .changeset/initial-release.md | Adds changeset for the initial release. |
| .vscode/mcp.json | Adds workspace MCP server configuration. |
| ciscode-ui-chart-kit-0.1.0.tgz | Adds a packed tarball artifact to the repo. |
| ciscode-reactts-developerkit-1.0.0.tgz | Adds a packed tarball artifact to the repo. |
| } from '../types/chart.types'; | ||
|
|
||
| function resolveColor(dataset: ChartDataset, index: number, theme: ChartTheme): string { | ||
| return dataset.color ?? theme.colors[index % theme.colors.length]; |
There was a problem hiding this comment.
resolveColor can return undefined when theme.colors is an empty array (because index % theme.colors.length becomes NaN), which then propagates into backgroundColor/borderColor and can produce invalid Chart.js config (e.g., 'undefined33' for area). Consider enforcing theme.colors to be non-empty (type-level and/or runtime check) and throwing a clear error or providing a safe fallback when it is empty.
| return dataset.color ?? theme.colors[index % theme.colors.length]; | |
| if (dataset.color) { | |
| return dataset.color; | |
| } | |
| if (theme.colors.length === 0) { | |
| throw new Error('Chart theme.colors must contain at least one color when dataset.color is not provided.'); | |
| } | |
| return theme.colors[index % theme.colors.length]; |
| function applyAreaOpacity(hex: string): string { | ||
| return `${hex}33`; | ||
| } | ||
|
|
There was a problem hiding this comment.
applyAreaOpacity blindly appends 33 to the input string. If a consumer passes a non-6-digit hex (e.g., #abc), an already-alpha hex (#RRGGBBAA), or an rgb(...)/CSS var, the resulting color becomes invalid. Either validate/normalize to #RRGGBB before appending, or switch to generating rgba(...) / using a color utility that can handle different formats.
| function applyAreaOpacity(hex: string): string { | |
| return `${hex}33`; | |
| } | |
| function normalizeHexColor(color: string): string | null { | |
| const shortHexMatch = /^#([\da-fA-F]{3})$/.exec(color); | |
| if (shortHexMatch) { | |
| const [r, g, b] = shortHexMatch[1].split(''); | |
| return `#${r}${r}${g}${g}${b}${b}`; | |
| } | |
| if (/^#([\da-fA-F]{6})$/.test(color)) { | |
| return color; | |
| } | |
| return null; | |
| } | |
| function applyAreaOpacity(color: string): string { | |
| const normalizedHex = normalizeHexColor(color); | |
| return normalizedHex ? `${normalizedHex}33` : color; | |
| } |
| @@ -0,0 +1,59 @@ | |||
| import { describe, it, expect, vi } from 'vitest'; | |||
| import { render, screen } from '@testing-library/react'; | |||
There was a problem hiding this comment.
screen is imported but never used in this test file. With the current ESLint config (@typescript-eslint/no-unused-vars: 'warn' and --max-warnings=0), this will fail npm run lint. Remove the unused import or use it in an assertion.
| import { render, screen } from '@testing-library/react'; | |
| import { render } from '@testing-library/react'; |
| @@ -0,0 +1,93 @@ | |||
| import { describe, it, expect, vi } from 'vitest'; | |||
| import { render, screen } from '@testing-library/react'; | |||
There was a problem hiding this comment.
screen is imported but never used in this test file. With the current ESLint config (@typescript-eslint/no-unused-vars: 'warn' and --max-warnings=0), this will fail npm run lint. Remove the unused import or use it in an assertion.
| import { render, screen } from '@testing-library/react'; | |
| import { render } from '@testing-library/react'; |
| @@ -0,0 +1,95 @@ | |||
| import { describe, it, expect, vi } from 'vitest'; | |||
| import { render, screen } from '@testing-library/react'; | |||
There was a problem hiding this comment.
screen is imported but never used in this test file. With the current ESLint config (@typescript-eslint/no-unused-vars: 'warn' and --max-warnings=0), this will fail npm run lint. Remove the unused import or use it in an assertion.
| import { render, screen } from '@testing-library/react'; | |
| import { render } from '@testing-library/react'; |
| "servers": { | ||
| "github": { | ||
| "command": "npx", | ||
| "args": ["-y", "@modelcontextprotocol/server-github"] | ||
| } | ||
| } |
There was a problem hiding this comment.
Adding .vscode/mcp.json hardcodes a local editor/MCP setup that runs npx -y @modelcontextprotocol/server-github. Committing this can create an unexpected supply-chain execution path for anyone opening the workspace. Prefer documenting optional MCP setup in CONTRIBUTING/README and keeping editor-specific config out of the repo (or at least require explicit opt-in).
| "servers": { | |
| "github": { | |
| "command": "npx", | |
| "args": ["-y", "@modelcontextprotocol/server-github"] | |
| } | |
| } | |
| "servers": {} |
| "types": "./dist/index.d.ts", | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "peerDependencies": { | ||
| "react": ">=18", | ||
| "react-dom": ">=18" | ||
| }, | ||
| "devDependencies": { | ||
| "@changesets/cli": "^2.27.8", | ||
| "@eslint/js": "^9.39.2", | ||
| "@testing-library/jest-dom": "^6.9.1", | ||
| "@testing-library/react": "^16.3.2", | ||
| "@testing-library/user-event": "^14.6.1", | ||
| "@types/react": "^18.3.12", | ||
| "@types/react-dom": "^18.3.1", | ||
| "@vitest/coverage-v8": "^2.1.8", | ||
| "@vitest/ui": "^2.1.8", | ||
| "eslint": "^9.39.2", | ||
| "eslint-config-prettier": "^10.1.8", | ||
| "eslint-plugin-react": "^7.37.5", | ||
| "eslint-plugin-react-hooks": "^7.0.1", | ||
| "globals": "^17.4.0", | ||
| "husky": "^9.1.7", | ||
| "jsdom": "^28.0.0", | ||
| "lint-staged": "^15.2.10", | ||
| "prettier": "^3.4.2", | ||
| "rimraf": "^6.0.1", | ||
| "tsup": "^8.3.5", | ||
| "typescript": "^5.7.2", | ||
| "typescript-eslint": "^8.55.0", | ||
| "vitest": "^2.1.8" | ||
| }, | ||
| "scripts": { | ||
| "clean": "rimraf dist *.tsbuildinfo && rm -rf coverage", | ||
| "build": "tsup", | ||
| "dev": "tsup --watch", | ||
| "lint": "eslint . --max-warnings=0", | ||
| "lint:fix": "eslint . --fix", | ||
| "typecheck": "tsc -p tsconfig.json --noEmit", | ||
| "test": "vitest run", | ||
| "test:watch": "vitest", | ||
| "test:cov": "vitest run --coverage", | ||
| "format": "prettier . --check", | ||
| "format:write": "prettier . --write", | ||
| "verify": "npm run lint && npm run typecheck && npm run test:cov", | ||
| "changeset": "changeset", | ||
| "version-packages": "changeset version", | ||
| "release": "changeset publish", | ||
| "prepublishOnly": "npm run verify && npm run build", | ||
| "prepare": "husky" | ||
| }, | ||
| "lint-staged": { | ||
| "*.{ts,tsx,js,jsx,json,md,yml,yaml}": [ | ||
| "prettier --write" | ||
| ], | ||
| "*.{ts,tsx,js,jsx}": [ | ||
| "eslint . --fix" | ||
| ] | ||
| }, | ||
| "engines": { | ||
| "node": ">=20" | ||
| }, |
There was a problem hiding this comment.
chart.js and react-chartjs-2 are added as runtime dependencies. Given tsup.config.ts only externalizes react/react-dom, these will likely be bundled into your distributed build, which can significantly increase bundle size and can lead to duplicate Chart.js copies if consumers also depend on it. Consider moving them to peerDependencies (and adding them to external) if you want consumers to share a single instance, or explicitly documenting that they are intentionally bundled.
| "name": "@ciscode/ui-chart-kit", | ||
| "version": "0.0.0", | ||
| "description": "React 19 chart library on Chart.js.", | ||
| "version": "0.1.0", | ||
| "description": "Typed React chart components (Bar, Line, Area) built on Chart.js — no raw Chart.js config required.", | ||
| "license": "MIT", | ||
| "private": false, |
There was a problem hiding this comment.
The PR description is still the default template and doesn’t describe the substantial changes here (new chart components, new public types, package rename). Please update the PR description (Summary/Why/Notes) so reviewers and release tooling have the correct context.
| | `react-dom` | ≥ 18 | | ||
|
|
||
| Anything not exported from `src/index.ts` is considered private. | ||
| `chart.js` and `react-chartjs-2` are bundled — you do **not** need to install them separately. |
There was a problem hiding this comment.
README says "chart.js and react-chartjs-2 are bundled". In package.json they are declared as dependencies, which means they are installed automatically but not necessarily bundled into the output (that depends on the build config). Consider rephrasing to avoid ambiguity (e.g., "installed automatically as dependencies" or explicitly state whether they are bundled into dist).
| `chart.js` and `react-chartjs-2` are bundled — you do **not** need to install them separately. | |
| `chart.js` and `react-chartjs-2` are installed automatically as dependencies — you do **not** need to install them separately. |
| } | ||
|
|
||
| export interface ChartTheme { | ||
| colors: string[]; |
There was a problem hiding this comment.
ChartTheme.colors is typed as string[], which allows an empty array, but buildChartConfig assumes at least one color (it indexes into theme.colors). Consider tightening this type to a non-empty tuple (e.g. [string, ...string[]]) and/or documenting/enforcing the non-empty requirement to prevent runtime invalid colors/config.
| colors: string[]; | |
| colors: [string, ...string[]]; |


Summary
Why
Checklist
npm run lintpassesnpm run typecheckpassesnpm testpassesnpm run buildpassesnpx changeset) if this affects consumersNotes