@internetstiftelsen/charts 0.6.1 → 0.7.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/types.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ export type DeepPartial<T> = {
2
+ [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
3
+ };
1
4
  export type DataValue = string | number | boolean | Date | null | undefined;
2
5
  export type DataItem = Record<string, any>;
3
6
  export type GroupedDataGroup = {
@@ -112,6 +115,39 @@ export type ChartTheme = {
112
115
  };
113
116
  };
114
117
  };
118
+ export type ResponsiveBreakpoints = Record<string, number>;
119
+ export type ResponsiveRenderContext = {
120
+ width: number;
121
+ height: number;
122
+ breakpoint: string | null;
123
+ };
124
+ export type ResponsiveComponentSnapshot = {
125
+ index: number;
126
+ type: string;
127
+ dataKey?: string;
128
+ currentConfig: Record<string, unknown>;
129
+ };
130
+ export type ResponsiveBeforeRenderState = {
131
+ theme: ChartTheme;
132
+ components: ResponsiveComponentSnapshot[];
133
+ };
134
+ export type ResponsiveComponentMatch = {
135
+ index?: number;
136
+ type?: string;
137
+ dataKey?: string;
138
+ };
139
+ export type ResponsiveComponentOverride = {
140
+ match: ResponsiveComponentMatch;
141
+ override: Record<string, unknown>;
142
+ };
143
+ export type ResponsiveBeforeRenderResult = {
144
+ theme?: DeepPartial<ChartTheme>;
145
+ components?: ResponsiveComponentOverride[];
146
+ };
147
+ export type ResponsiveConfig = {
148
+ breakpoints?: ResponsiveBreakpoints;
149
+ beforeRender?: (context: ResponsiveRenderContext, state: ResponsiveBeforeRenderState) => void | ResponsiveBeforeRenderResult;
150
+ };
115
151
  export type ValueLabelConfig = {
116
152
  fontSize?: number;
117
153
  fontFamily?: string;
@@ -227,7 +263,9 @@ export type TooltipConfig = TooltipConfigBase & {
227
263
  exportHooks?: ExportHooks<TooltipConfigBase>;
228
264
  };
229
265
  export type LegendConfigBase = {
266
+ mode?: LegendMode;
230
267
  position?: 'bottom';
268
+ disconnectedTarget?: string | HTMLElement;
231
269
  marginTop?: number;
232
270
  marginBottom?: number;
233
271
  paddingX?: number;
@@ -242,6 +280,12 @@ export type LegendSeries = {
242
280
  stroke?: string;
243
281
  fill?: string;
244
282
  };
283
+ export type LegendMode = 'inline' | 'disconnected' | 'hidden';
284
+ export type LegendItem = {
285
+ dataKey: string;
286
+ color: string;
287
+ visible: boolean;
288
+ };
245
289
  export type TitleConfigBase = {
246
290
  text: string;
247
291
  fontSize?: number;
package/utils.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  import { type ClassValue } from 'clsx';
2
+ import type { DeepPartial } from './types.js';
3
+ export { toChartData } from './grouped-tabular.js';
4
+ export type { GroupedStringParseOptions, ToChartDataOptions, } from './grouped-tabular.js';
2
5
  export declare function cn(...inputs: ClassValue[]): string;
3
6
  /**
4
7
  * Sanitizes a string to be used as a CSS class name or ID.
@@ -61,4 +64,4 @@ export declare function breakWord(word: string, maxWidth: number, fontSize: stri
61
64
  */
62
65
  export declare function wrapText(text: string, maxWidth: number, fontSize: string | number, fontFamily: string, fontWeight: string, svg: SVGSVGElement): string[];
63
66
  export declare function getContrastTextColor(backgroundColor: string, lightTextColor?: string, darkTextColor?: string): string;
64
- export declare function mergeDeep<T extends Record<string, unknown>>(base: T, override?: Partial<T>): T;
67
+ export declare function mergeDeep<T extends Record<string, unknown>>(base: T, override?: DeepPartial<T>): T;
package/utils.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { twMerge } from 'tailwind-merge';
3
+ export { toChartData } from './grouped-tabular.js';
3
4
  export function cn(...inputs) {
4
5
  return twMerge(clsx(inputs));
5
6
  }
package/xy-chart.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { BaseChart, type BaseChartConfig } from './base-chart.js';
2
2
  import type { ChartComponent } from './chart-interface.js';
3
- import { type AreaStackConfig, type BarStackConfig } from './types.js';
3
+ import { type AreaStackConfig, type BarStackConfig, type LegendSeries } from './types.js';
4
4
  export type XYChartConfig = BaseChartConfig & {
5
5
  barStack?: BarStackConfig;
6
6
  areaStack?: AreaStackConfig;
@@ -14,11 +14,12 @@ export declare class XYChart extends BaseChart {
14
14
  addChild(component: ChartComponent): this;
15
15
  protected getExportComponents(): ChartComponent[];
16
16
  protected createExportChart(): BaseChart;
17
+ protected applyComponentOverrides(overrides: Map<ChartComponent, ChartComponent>): () => void;
17
18
  private rerender;
18
19
  protected prepareLayout(): void;
19
20
  protected renderChart(): void;
20
21
  private getXKey;
21
- private getLegendSeries;
22
+ protected getLegendSeries(): LegendSeries[];
22
23
  private getCategoryScaleType;
23
24
  private getVisibleSeries;
24
25
  private setupScales;
package/xy-chart.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { max, min, scaleBand, scaleLinear, scaleLog, scaleTime, } from 'd3';
2
2
  import { BaseChart } from './base-chart.js';
3
3
  import { ChartValidator } from './validation.js';
4
- import { GROUPED_GAP_TICK_PREFIX, GROUPED_GROUP_LABEL_KEY } from './grouped-data.js';
4
+ import { GROUPED_GAP_TICK_PREFIX, GROUPED_GROUP_LABEL_KEY, } from './grouped-data.js';
5
5
  export class XYChart extends BaseChart {
6
6
  constructor(config) {
7
7
  super(config);
@@ -116,6 +116,7 @@ export class XYChart extends BaseChart {
116
116
  data: this.data,
117
117
  theme: this.theme,
118
118
  scales: this.scaleConfig,
119
+ responsive: this.responsiveConfig,
119
120
  barStack: {
120
121
  mode: this.barStackMode,
121
122
  gap: this.barStackGap,
@@ -125,7 +126,30 @@ export class XYChart extends BaseChart {
125
126
  },
126
127
  });
127
128
  }
129
+ applyComponentOverrides(overrides) {
130
+ const restoreBase = super.applyComponentOverrides(overrides);
131
+ if (overrides.size === 0) {
132
+ return restoreBase;
133
+ }
134
+ const previousSeries = [...this.series];
135
+ this.series.forEach((series, index) => {
136
+ const override = overrides.get(series);
137
+ if (override &&
138
+ (override.type === 'line' ||
139
+ override.type === 'bar' ||
140
+ override.type === 'area')) {
141
+ this.series[index] = override;
142
+ }
143
+ });
144
+ return () => {
145
+ this.series.splice(0, this.series.length, ...previousSeries);
146
+ restoreBase();
147
+ };
148
+ }
128
149
  rerender() {
150
+ if (!this.container) {
151
+ return;
152
+ }
129
153
  this.update(this.sourceData);
130
154
  }
131
155
  prepareLayout() {
@@ -142,7 +166,7 @@ export class XYChart extends BaseChart {
142
166
  });
143
167
  this.xAxis.estimateLayoutSpace?.(labels, this.theme, svgNode);
144
168
  }
145
- if (svgNode && this.legend) {
169
+ if (svgNode && this.legend?.isInlineMode()) {
146
170
  this.legend.estimateLayoutSpace(this.getLegendSeries(), this.theme, this.width, svgNode);
147
171
  }
148
172
  }
@@ -199,7 +223,7 @@ export class XYChart extends BaseChart {
199
223
  this.tooltip.initialize(this.theme);
200
224
  this.tooltip.attachToArea(this.svg, this.data, visibleSeries, xKey, this.x, this.y, this.theme, this.plotArea, this.parseValue.bind(this), this.isHorizontalOrientation(), categoryScaleType, (series, dataPoint) => this.getSeriesTooltipValue(series, dataPoint, xKey, areaStackingContextBySeries));
201
225
  }
202
- if (this.legend) {
226
+ if (this.legend?.isInlineMode()) {
203
227
  const legendPos = this.layoutManager.getComponentPosition(this.legend);
204
228
  this.legend.render(this.svg, this.getLegendSeries(), this.theme, this.width, legendPos.x, legendPos.y);
205
229
  }
@@ -481,7 +505,9 @@ export class XYChart extends BaseChart {
481
505
  const areaSeries = visibleSeries.filter((s) => s.type === 'area');
482
506
  const lineSeries = visibleSeries.filter((s) => s.type === 'line');
483
507
  const areaValueLabelLayer = areaSeries.length > 0
484
- ? this.plotGroup.append('g').attr('class', 'area-value-label-layer')
508
+ ? this.plotGroup
509
+ .append('g')
510
+ .attr('class', 'area-value-label-layer')
485
511
  : null;
486
512
  const { cumulativeDataBySeriesIndex, totalData } = this.computeStackingData(this.data, xKey, barSeries);
487
513
  const areaStackingContextBySeries = this.computeAreaStackingContexts(this.data, xKey, areaSeries);