@opendata-ai/openchart-core 7.1.4 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +31 -1
- package/dist/index.js +43 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/colors/palettes.ts +11 -8
- package/src/theme/__tests__/resolve.test.ts +20 -0
- package/src/theme/defaults.ts +2 -0
- package/src/theme/resolve.ts +28 -0
- package/src/types/spec.ts +23 -0
- package/src/types/theme.ts +4 -0
package/dist/index.d.ts
CHANGED
|
@@ -334,6 +334,8 @@ interface AxisConfig {
|
|
|
334
334
|
labelPadding?: number;
|
|
335
335
|
/** Color override for axis tick labels and title. Useful in dual-axis charts to match axis color to its series. */
|
|
336
336
|
labelColor?: string;
|
|
337
|
+
/** Literal string appended to every formatted tick label. e.g. "B" gives "$4.5B" when format is "$,.1~f". */
|
|
338
|
+
labelSuffix?: string;
|
|
337
339
|
/** Secondary data field to display alongside each tick label. Renders in lighter weight/color. Only effective on categorical y-axis labels (horizontal bar charts). */
|
|
338
340
|
labelField?: string;
|
|
339
341
|
/**
|
|
@@ -847,6 +849,19 @@ interface ThemeConfig {
|
|
|
847
849
|
family?: string;
|
|
848
850
|
/** Monospace font family (for tabular numbers). */
|
|
849
851
|
mono?: string;
|
|
852
|
+
/** Font size overrides in pixels. Partial — only specified keys are overridden. */
|
|
853
|
+
sizes?: {
|
|
854
|
+
/** Chart title. Default: 26. */
|
|
855
|
+
title?: number;
|
|
856
|
+
/** Subtitle below the title. Default: 14. */
|
|
857
|
+
subtitle?: number;
|
|
858
|
+
/** Body text (tooltips, legend labels). Default: 13. */
|
|
859
|
+
body?: number;
|
|
860
|
+
/** Small text (source line, footer). Default: 11. */
|
|
861
|
+
small?: number;
|
|
862
|
+
/** Axis tick labels. Default: 11. */
|
|
863
|
+
axisTick?: number;
|
|
864
|
+
};
|
|
850
865
|
};
|
|
851
866
|
/** Spacing overrides in pixels. */
|
|
852
867
|
spacing?: {
|
|
@@ -854,6 +869,10 @@ interface ThemeConfig {
|
|
|
854
869
|
padding?: number;
|
|
855
870
|
/** Gap between chrome elements (title to subtitle, etc.). */
|
|
856
871
|
chromeGap?: number;
|
|
872
|
+
/** Height reserved below chart area for x-axis tick labels. Increase when large axisTick font sizes cause label clipping. */
|
|
873
|
+
xAxisHeight?: number;
|
|
874
|
+
/** Gap in pixels between the x-axis line and tick label text. Increase when larger axisTick fonts sit too close to the axis line. */
|
|
875
|
+
xAxisLabelPadding?: number;
|
|
857
876
|
};
|
|
858
877
|
/** Border radius for chart container and tooltips. */
|
|
859
878
|
borderRadius?: number;
|
|
@@ -894,10 +913,14 @@ interface LabelConfig {
|
|
|
894
913
|
format?: string;
|
|
895
914
|
/** Literal string prepended to each formatted label value (e.g. "-" or "$"). */
|
|
896
915
|
prefix?: string;
|
|
916
|
+
/** Literal string appended to each formatted label value (e.g. "%" or "x"). */
|
|
917
|
+
suffix?: string;
|
|
897
918
|
/** Fixed CSS color for all labels. Overrides the default fill-derived color. */
|
|
898
919
|
color?: string;
|
|
899
920
|
/** Per-series pixel offsets for fine-tuning label positions, keyed by series name. */
|
|
900
921
|
offsets?: Record<string, AnnotationOffset>;
|
|
922
|
+
/** Font size in pixels for bar/column value labels. */
|
|
923
|
+
fontSize?: number;
|
|
901
924
|
}
|
|
902
925
|
/** Shorthand: `false` disables all labels, `true` uses defaults, or pass a full config object. */
|
|
903
926
|
type LabelSpec = boolean | LabelConfig;
|
|
@@ -2220,6 +2243,10 @@ interface ThemeSpacing {
|
|
|
2220
2243
|
chartToFooter: number;
|
|
2221
2244
|
/** Internal padding within the chart area (axes margins). */
|
|
2222
2245
|
axisMargin: number;
|
|
2246
|
+
/** Height reserved below the chart area for x-axis tick labels (and optional axis title). */
|
|
2247
|
+
xAxisHeight: number;
|
|
2248
|
+
/** Gap in pixels between the x-axis line and the top of non-rotated tick label text. */
|
|
2249
|
+
xAxisLabelPadding: number;
|
|
2223
2250
|
}
|
|
2224
2251
|
/** Default style configuration for a chrome text element. */
|
|
2225
2252
|
interface ChromeDefaults {
|
|
@@ -3653,8 +3680,11 @@ declare function findAccessibleColor(baseColor: string, bg: string, targetRatio?
|
|
|
3653
3680
|
* -> sRGB pipeline. Documented OKLCH source values are the contract; if
|
|
3654
3681
|
* the conversion math changes, regenerate from the source rather than
|
|
3655
3682
|
* editing hex literals directly.
|
|
3683
|
+
*
|
|
3684
|
+
* Tuned at L≈0.65, C≈0.20 (vs prior L≈0.70, C≈0.15) for more vivid,
|
|
3685
|
+
* saturated color on dark backgrounds where the lighter pastels read soft.
|
|
3656
3686
|
*/
|
|
3657
|
-
declare const CATEGORICAL_PALETTE: readonly ["#06b6d4", "#
|
|
3687
|
+
declare const CATEGORICAL_PALETTE: readonly ["#06b6d4", "#ee4a73", "#00b054", "#a46bf5", "#e07d00", "#0091ff", "#f36000", "#6f7dff", "#00afbf"];
|
|
3658
3688
|
type CategoricalPalette = typeof CATEGORICAL_PALETTE;
|
|
3659
3689
|
/** Sequential palette definition: an array of color stops from light to dark. */
|
|
3660
3690
|
interface SequentialPalette {
|
package/dist/index.js
CHANGED
|
@@ -726,22 +726,22 @@ var ACHROMATIC_RAMP = {
|
|
|
726
726
|
var CATEGORICAL_PALETTE = [
|
|
727
727
|
"#06b6d4",
|
|
728
728
|
// cyan, primary accent (sRGB literal, ~205°)
|
|
729
|
-
"#
|
|
730
|
-
// rose — oklch(
|
|
731
|
-
"#
|
|
732
|
-
// emerald — oklch(
|
|
733
|
-
"#
|
|
734
|
-
// violet — oklch(
|
|
735
|
-
"#
|
|
736
|
-
// amber — oklch(
|
|
737
|
-
"#
|
|
738
|
-
// sky — oklch(
|
|
739
|
-
"#
|
|
740
|
-
// orange — oklch(
|
|
741
|
-
"#
|
|
742
|
-
// indigo — oklch(
|
|
743
|
-
"#
|
|
744
|
-
// teal — oklch(
|
|
729
|
+
"#ee4a73",
|
|
730
|
+
// rose — oklch(65% 0.20 10)
|
|
731
|
+
"#00b054",
|
|
732
|
+
// emerald — oklch(65% 0.20 155)
|
|
733
|
+
"#a46bf5",
|
|
734
|
+
// violet — oklch(65% 0.20 300)
|
|
735
|
+
"#e07d00",
|
|
736
|
+
// amber — oklch(68% 0.19 70)
|
|
737
|
+
"#0091ff",
|
|
738
|
+
// sky — oklch(65% 0.20 250)
|
|
739
|
+
"#f36000",
|
|
740
|
+
// orange — oklch(67% 0.20 45)
|
|
741
|
+
"#6f7dff",
|
|
742
|
+
// indigo — oklch(65% 0.20 275)
|
|
743
|
+
"#00afbf"
|
|
744
|
+
// teal — oklch(65% 0.20 200)
|
|
745
745
|
];
|
|
746
746
|
var SEQUENTIAL_BLUE = {
|
|
747
747
|
name: "blue",
|
|
@@ -853,7 +853,9 @@ var DEFAULT_THEME = {
|
|
|
853
853
|
chromeGap: 4,
|
|
854
854
|
chromeToChart: 8,
|
|
855
855
|
chartToFooter: 8,
|
|
856
|
-
axisMargin: 6
|
|
856
|
+
axisMargin: 6,
|
|
857
|
+
xAxisHeight: 26,
|
|
858
|
+
xAxisLabelPadding: 14
|
|
857
859
|
},
|
|
858
860
|
borderRadius: 2,
|
|
859
861
|
chrome: {
|
|
@@ -1048,12 +1050,16 @@ function themeConfigToPartial(config) {
|
|
|
1048
1050
|
const fonts = {};
|
|
1049
1051
|
if (config.fonts.family) fonts.family = config.fonts.family;
|
|
1050
1052
|
if (config.fonts.mono) fonts.mono = config.fonts.mono;
|
|
1053
|
+
if (config.fonts.sizes) fonts.sizes = config.fonts.sizes;
|
|
1051
1054
|
partial.fonts = fonts;
|
|
1052
1055
|
}
|
|
1053
1056
|
if (config.spacing) {
|
|
1054
1057
|
const spacing = {};
|
|
1055
1058
|
if (config.spacing.padding !== void 0) spacing.padding = config.spacing.padding;
|
|
1056
1059
|
if (config.spacing.chromeGap !== void 0) spacing.chromeGap = config.spacing.chromeGap;
|
|
1060
|
+
if (config.spacing.xAxisHeight !== void 0) spacing.xAxisHeight = config.spacing.xAxisHeight;
|
|
1061
|
+
if (config.spacing.xAxisLabelPadding !== void 0)
|
|
1062
|
+
spacing.xAxisLabelPadding = config.spacing.xAxisLabelPadding;
|
|
1057
1063
|
partial.spacing = spacing;
|
|
1058
1064
|
}
|
|
1059
1065
|
if (config.borderRadius !== void 0) {
|
|
@@ -1123,6 +1129,26 @@ function adjustOpacity(hex2, opacity) {
|
|
|
1123
1129
|
}
|
|
1124
1130
|
function resolveTheme(userTheme, base = DEFAULT_THEME) {
|
|
1125
1131
|
let merged = userTheme ? deepMerge(base, themeConfigToPartial(userTheme)) : { ...base };
|
|
1132
|
+
if (userTheme?.fonts?.sizes) {
|
|
1133
|
+
const s = userTheme.fonts.sizes;
|
|
1134
|
+
merged = {
|
|
1135
|
+
...merged,
|
|
1136
|
+
chrome: {
|
|
1137
|
+
...merged.chrome,
|
|
1138
|
+
...s.title !== void 0 && {
|
|
1139
|
+
title: { ...merged.chrome.title, fontSize: s.title }
|
|
1140
|
+
},
|
|
1141
|
+
...s.subtitle !== void 0 && {
|
|
1142
|
+
subtitle: { ...merged.chrome.subtitle, fontSize: s.subtitle }
|
|
1143
|
+
},
|
|
1144
|
+
...s.small !== void 0 && {
|
|
1145
|
+
source: { ...merged.chrome.source, fontSize: s.small },
|
|
1146
|
+
byline: { ...merged.chrome.byline, fontSize: s.small },
|
|
1147
|
+
footer: { ...merged.chrome.footer, fontSize: s.small }
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1126
1152
|
const dark = isDarkBackground(merged.colors.background);
|
|
1127
1153
|
if (dark) {
|
|
1128
1154
|
merged = adaptChromeForDarkBg(merged, merged.colors.text);
|