Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/legacy-compat.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`@policyengine/ui-kit/legacy` compatibility shim that mirrors the API surface of the deprecated `@policyengine/design-system` package. Migrating from design-system is now a pure import-path rename: `@policyengine/design-system` → `@policyengine/ui-kit/legacy`, with matching subpath exports for `/tokens`, `/tokens/colors`, `/tokens/typography`, `/tokens/spacing`, and `/charts`. All legacy exports carry `@deprecated` JSDoc pointing at the canonical ui-kit equivalents (`palette`, `semanticFills`, `typography`, `namedSpacing`, `chartPalette`, etc.).
30 changes: 30 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,36 @@
"import": "./dist/assets.js",
"require": "./dist/assets.cjs"
},
"./legacy": {
"types": "./dist/legacy/index.d.ts",
"import": "./dist/legacy.js",
"require": "./dist/legacy.cjs"
},
"./legacy/tokens": {
"types": "./dist/legacy/tokens/index.d.ts",
"import": "./dist/legacy/tokens.js",
"require": "./dist/legacy/tokens.cjs"
},
"./legacy/tokens/colors": {
"types": "./dist/legacy/tokens/colors.d.ts",
"import": "./dist/legacy/tokens/colors.js",
"require": "./dist/legacy/tokens/colors.cjs"
},
"./legacy/tokens/typography": {
"types": "./dist/legacy/tokens/typography.d.ts",
"import": "./dist/legacy/tokens/typography.js",
"require": "./dist/legacy/tokens/typography.cjs"
},
"./legacy/tokens/spacing": {
"types": "./dist/legacy/tokens/spacing.d.ts",
"import": "./dist/legacy/tokens/spacing.js",
"require": "./dist/legacy/tokens/spacing.cjs"
},
"./legacy/charts": {
"types": "./dist/legacy/charts/index.d.ts",
"import": "./dist/legacy/charts.js",
"require": "./dist/legacy/charts.cjs"
},
"./styles.css": "./dist/styles.css",
"./theme.css": "./src/theme/tokens.css",
"./quarto.scss": "./src/theme/quarto.scss",
Expand Down
212 changes: 212 additions & 0 deletions src/legacy/charts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
/**
* @deprecated Compatibility shim mirroring `@policyengine/design-system/charts`.
* These are Plotly-flavored helpers. For new code, use the canonical Recharts
* components (`PEBarChart`, `PELineChart`, `PEAreaChart`, `PEWaterfallChart`)
* and chart defaults (`AXIS_STYLE`, `chartColors`) from
* `@policyengine/ui-kit/charts`, plus `chartPalette` (resolved hex per
* theme) from `@policyengine/ui-kit`.
*
* PolicyEngine Chart Utilities
* Shared chart formatting for Plotly.js charts
*/

import { colors, TEAL_PRIMARY } from "../tokens/colors";
import { typography } from "../tokens/typography";

/**
* Standard chart colors for PolicyEngine visualizations
*/
export const chartColors = {
primary: TEAL_PRIMARY,
secondary: colors.gray[400],
baseline: colors.gray[300],
positive: TEAL_PRIMARY,
negative: colors.error,
neutral: colors.gray[500],
// For multi-series charts
series: [
TEAL_PRIMARY,
colors.gray[500],
colors.primary[700],
colors.gray[700],
colors.primary[300],
],
} as const;

/**
* Standard Plotly layout configuration for PolicyEngine charts
*/
export const chartLayout = {
font: {
family: typography.fontFamily.chart,
color: colors.text.primary,
size: 14,
},
paper_bgcolor: colors.white,
plot_bgcolor: colors.white,
margin: {
l: 60,
r: 40,
t: 40,
b: 60,
},
showlegend: true,
legend: {
orientation: "h" as const,
yanchor: "bottom" as const,
y: 1.02,
xanchor: "right" as const,
x: 1,
},
xaxis: {
gridcolor: colors.border.light,
zerolinecolor: colors.border.medium,
},
yaxis: {
gridcolor: colors.border.light,
zerolinecolor: colors.border.medium,
},
} as const;

/**
* Standard chart dimensions
*/
export const chartDimensions = {
default: {
width: 800,
height: 600,
},
compact: {
width: 600,
height: 400,
},
wide: {
width: 1000,
height: 500,
},
square: {
width: 600,
height: 600,
},
} as const;

/**
* PolicyEngine logo image configuration for chart watermarks
*/
export const chartLogo = {
source: "/assets/logos/policyengine/teal-square.png",
xref: "paper" as const,
yref: "paper" as const,
x: 1,
y: 0,
sizex: 0.1,
sizey: 0.1,
xanchor: "right" as const,
yanchor: "bottom" as const,
opacity: 0.8,
} as const;

/**
* Format configuration object for creating Plotly charts
* Compatible with both React (react-plotly.js) and Python (plotly.py)
*/
export interface ChartConfig {
layout: typeof chartLayout;
config: {
displayModeBar: boolean;
responsive: boolean;
};
style: {
width: string;
height: string;
};
}

export function getChartConfig(
dimensions: keyof typeof chartDimensions = "default",
): ChartConfig {
const dims = chartDimensions[dimensions];
return {
layout: chartLayout,
config: {
displayModeBar: false,
responsive: true,
},
style: {
width: `${dims.width}px`,
height: `${dims.height}px`,
},
};
}

/**
* Currency formatter for chart axis labels
*/
export function formatCurrency(value: number): string {
if (Math.abs(value) >= 1e9) {
return `$${(value / 1e9).toFixed(1)}B`;
}
if (Math.abs(value) >= 1e6) {
return `$${(value / 1e6).toFixed(1)}M`;
}
if (Math.abs(value) >= 1e3) {
return `$${(value / 1e3).toFixed(0)}K`;
}
return `$${value.toFixed(0)}`;
}

/**
* Percentage formatter for chart axis labels
*/
export function formatPercent(value: number, decimals: number = 0): string {
return `${(value * 100).toFixed(decimals)}%`;
}

// ---------------------------------------------------------------------------
// Nice tick generation (D3-style)
// ---------------------------------------------------------------------------

const NICE_STEPS = [1, 2, 2.5, 5, 10];

/**
* Compute a "nice" step size for axis ticks by snapping to {1, 2, 2.5, 5}
* multiples at each order of magnitude.
*/
function niceStep(roughStep: number): number {
if (roughStep <= 0) {
return 1;
}
const exponent = Math.floor(Math.log10(roughStep));
const magnitude = 10 ** exponent;
const normalized = roughStep / magnitude;
const nice = NICE_STEPS.find((s) => s >= normalized - 1e-10) ?? 10;
return nice * magnitude;
}

/**
* Generate nice tick values for a given domain and approximate tick count.
* Ticks are rounded to human-friendly numbers (multiples of 1, 2, 2.5, 5).
*
* @param domain - [min, max] data range
* @param count - Approximate number of ticks desired (default: 5)
* @returns Array of tick values
*/
export function getNiceTicks(domain: [number, number], count = 5): number[] {
const [dMin, dMax] = domain;
if (dMin === dMax) {
return [dMin];
}

const rawStep = (dMax - dMin) / Math.max(count - 1, 1);
const step = niceStep(rawStep);
const start = Math.floor(dMin / step) * step;
const ticks: number[] = [];

for (let v = start; v <= dMax + step * 0.01; v += step) {
// Round to avoid floating-point noise and negative zero
const rounded = Math.round(v * 1e10) / 1e10 || 0;
ticks.push(rounded);
}

return ticks;
}
32 changes: 32 additions & 0 deletions src/legacy/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* @policyengine/ui-kit/legacy
*
* @deprecated Backwards-compatibility shim that re-exports the API surface of
* the legacy `@policyengine/design-system` package. Use the canonical exports
* from `@policyengine/ui-kit` (root) and the `tokens` / `theme.css` /
* `quarto.scss` subpath exports for new code.
*
* This module exists to make the migration from `@policyengine/design-system`
* a pure import-path rename:
*
* - import … from '@policyengine/design-system' → '@policyengine/ui-kit/legacy'
* - import … from '@policyengine/design-system/tokens' → '@policyengine/ui-kit/legacy/tokens'
* - import … from '@policyengine/design-system/charts' → '@policyengine/ui-kit/legacy/charts'
* - import … from '@policyengine/design-system/tokens/colors' → '@policyengine/ui-kit/legacy/tokens/colors'
*
* Mapping to canonical ui-kit exports for net-new code:
*
* colors.primary[N] → palette.teal[N]
* colors.gray[N] → palette.gray[N]
* colors.warning → semanticFills.warning
* colors.error → semanticFills.error
* colors.text.warning → rootColorsLight['--text-warning'] (or `var(--text-warning)`)
* typography.fontFamily.primary → typography.fontFamily.sans
* spacing.{layout,…} → namedSpacing (only `header`, `sidebar`, `content` exposed today)
* chartColors / chartLayout → see charts/chartDefaults.ts (Recharts) or chartPalette (resolved hex)
*
* This module will be removed in a future major release once consumers migrate.
*/

export * from "./tokens";
export * from "./charts";
Loading