sk-chart-duo 0.1.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.
@@ -0,0 +1,520 @@
1
+ interface ExportOptions {
2
+ /** 'png' rasterizes through a canvas; 'svg' returns the vector markup as a data URL. */
3
+ type?: 'png' | 'svg';
4
+ /** Pixel-density multiplier for PNG output. */
5
+ scale?: number;
6
+ /** Canvas backdrop painted before drawing the SVG; omit for transparency. */
7
+ background?: string;
8
+ }
9
+ interface DownloadOptions extends ExportOptions {
10
+ filename?: string;
11
+ }
12
+
13
+ type ContainerLike = string | HTMLElement;
14
+ interface BaseConfig {
15
+ /** viewBox design-space width. */
16
+ width?: number;
17
+ /** viewBox design-space height. */
18
+ height?: number;
19
+ }
20
+ interface ColumnEventPayload<D = unknown> {
21
+ index: number;
22
+ datum: D;
23
+ }
24
+ interface ChartEventMap<D = unknown> {
25
+ 'column:enter': ColumnEventPayload<D>;
26
+ 'column:leave': ColumnEventPayload<D>;
27
+ 'column:click': ColumnEventPayload<D>;
28
+ }
29
+
30
+ /**
31
+ * Shared lifecycle for all chart classes: container resolution, config merge,
32
+ * full-rebuild update/resize, event bus and teardown.
33
+ *
34
+ * E is the chart-type-specific event map, so each chart declares its own events
35
+ * without touching core.
36
+ */
37
+ declare abstract class ChartBase<C extends BaseConfig, E extends object = ChartEventMap> {
38
+ protected container: HTMLElement;
39
+ protected config: C;
40
+ protected svg: SVGSVGElement | null;
41
+ private handlers;
42
+ private destroyed;
43
+ constructor(container: ContainerLike, config: C);
44
+ get isDestroyed(): boolean;
45
+ on<K extends keyof E & string>(event: K, handler: (payload: E[K]) => void): this;
46
+ off<K extends keyof E & string>(event: K, handler: (payload: E[K]) => void): this;
47
+ protected emit<K extends keyof E & string>(event: K, payload: E[K]): void;
48
+ /** Merges the partial config and rebuilds the chart. */
49
+ update(config: Partial<C>): void;
50
+ /** Changes the viewBox design space and rebuilds (userSpaceOnUse coordinates depend on it). */
51
+ resize(width: number, height: number): void;
52
+ /** Standalone SVG markup (embedded style + defs included), renderable as-is. */
53
+ toSVGString(): string;
54
+ /** Data URL of the current chart; PNG is rasterized through canvas at `scale` (default 2x). */
55
+ getDataURL(options?: ExportOptions): Promise<string>;
56
+ /** Triggers a browser download of the chart, PNG at 2x by default. */
57
+ download(options?: DownloadOptions): Promise<void>;
58
+ private requireSvg;
59
+ destroy(): void;
60
+ /** Subclasses build (or rebuild) the SVG and attach it to the container. */
61
+ protected abstract renderChart(): void;
62
+ /** Subclass teardown hook, called before the SVG is removed. */
63
+ protected onDestroy(): void;
64
+ }
65
+
66
+ type GradientStop = readonly [offset: number, color: string];
67
+
68
+ interface ResolvedFoldBarStyle {
69
+ stripePattern: StripePatternStyle;
70
+ barGradientActive: GradientStop[];
71
+ barGradientNormal: GradientStop[];
72
+ foldGradient: GradientStop[];
73
+ creaseGradient: GradientStop[];
74
+ washTop: number;
75
+ washGradient: GradientStop[];
76
+ washEnabled: boolean;
77
+ pill: PillStyle;
78
+ shadow: DropShadowStyle;
79
+ fadeMask: {
80
+ start: number;
81
+ end: number;
82
+ };
83
+ fadeEnabled: boolean;
84
+ labelY: number;
85
+ numberY: number;
86
+ labelXOffset: number;
87
+ }
88
+ interface FoldBarThemeTokens {
89
+ fontFamily: string;
90
+ title: {
91
+ fill: string;
92
+ fontSize: number;
93
+ fontWeight: number;
94
+ letterSpacing: string;
95
+ };
96
+ axis: {
97
+ fill: string;
98
+ fontSize: number;
99
+ fontWeight: number;
100
+ };
101
+ label: {
102
+ fill: string;
103
+ activeFill: string;
104
+ fontSize: number;
105
+ fontWeight: number;
106
+ };
107
+ number: {
108
+ fill: string;
109
+ activeFill: string;
110
+ fontSize: number;
111
+ fontWeight: number;
112
+ letterSpacing: string;
113
+ };
114
+ grid: {
115
+ stroke: string;
116
+ strokeWidth: number;
117
+ };
118
+ tooltip: {
119
+ bg: string;
120
+ stroke: string;
121
+ fill: string;
122
+ strongFill: string;
123
+ softFill: string;
124
+ fontSize: number;
125
+ };
126
+ transition: {
127
+ state: string;
128
+ tip: string;
129
+ };
130
+ }
131
+ /** Top-level optional theme override; nested token groups are partially overridable. */
132
+ type DeepPartialTokens = {
133
+ [K in keyof FoldBarThemeTokens]?: FoldBarThemeTokens[K] extends object ? Partial<FoldBarThemeTokens[K]> : FoldBarThemeTokens[K];
134
+ };
135
+
136
+ interface ThemeFormats {
137
+ valueFormat?: (value: number) => string;
138
+ tickFormat?: (value: number) => string;
139
+ }
140
+ /** A theme bundle: visual style, typography tokens and default formatters. */
141
+ interface ThemePack {
142
+ style?: FoldBarStyleConfig;
143
+ tokens?: DeepPartialTokens;
144
+ formats?: ThemeFormats;
145
+ }
146
+ /** Runtime type guard: pack keys are disjoint from DeepPartialTokens keys. */
147
+ declare function isThemePack(value: object): value is ThemePack;
148
+ /** Registers (or replaces) a named theme pack usable via `config.theme`. */
149
+ declare function registerTheme(name: string, pack: ThemePack): void;
150
+ declare function getTheme(name: string): ThemePack | undefined;
151
+
152
+ interface Padding {
153
+ top: number;
154
+ right: number;
155
+ bottom: number;
156
+ left: number;
157
+ }
158
+ interface PlotRect {
159
+ left: number;
160
+ right: number;
161
+ top: number;
162
+ bottom: number;
163
+ width: number;
164
+ height: number;
165
+ }
166
+ interface FoldBarLayout {
167
+ plot: PlotRect;
168
+ count: number;
169
+ colWidth: number;
170
+ barWidth: number;
171
+ /** Bar top y when value is 0. */
172
+ stairBase: number;
173
+ /** Bar top y of the domain maximum (top tick). */
174
+ stairTop: number;
175
+ /** Maximum data value. */
176
+ maxValue: number;
177
+ /** Axis domain maximum the bars normalize against. */
178
+ domainMax: number;
179
+ barTopOf: (value: number) => number;
180
+ }
181
+ interface BarGeometry {
182
+ /** Leading edge of the column band (hit area / grid line). */
183
+ colStart: number;
184
+ x: number;
185
+ y: number;
186
+ width: number;
187
+ height: number;
188
+ centerX: number;
189
+ }
190
+ interface FlapGeometry {
191
+ /** SVG polygon points attribute. */
192
+ points: string;
193
+ /** Crease segment: from current bar top to next bar top. */
194
+ crease: {
195
+ x1: number;
196
+ y1: number;
197
+ x2: number;
198
+ y2: number;
199
+ };
200
+ /** y range for the userSpaceOnUse fold gradient. */
201
+ gradientY: [number, number];
202
+ }
203
+ interface PillGeometry {
204
+ x: number;
205
+ y: number;
206
+ width: number;
207
+ height: number;
208
+ rx: number;
209
+ shadowX: number;
210
+ shadowY: number;
211
+ shadowWidth: number;
212
+ shadowHeight: number;
213
+ shadowRx: number;
214
+ }
215
+ interface RectGeometry {
216
+ x: number;
217
+ y: number;
218
+ width: number;
219
+ height: number;
220
+ }
221
+
222
+ interface FoldBarDatum {
223
+ label: string;
224
+ value: number;
225
+ [key: string]: unknown;
226
+ }
227
+ interface FoldBarScaleConfig {
228
+ /** Power applied to normalized values. 1 = linear; 2 reproduces the fold-funnel silhouette. */
229
+ exponent?: number;
230
+ }
231
+ interface FoldBarFoldConfig {
232
+ /** Horizontal run reserved for the paper fold between columns. */
233
+ run?: number;
234
+ creaseColor?: string;
235
+ creaseWidth?: number;
236
+ }
237
+ interface FoldBarAxisConfig {
238
+ /** Explicit tick values, e.g. [70, 60, 50, 40, 30]. Positions map via barTopOf. */
239
+ ticks?: number[];
240
+ tickFormat?: (value: number) => string;
241
+ }
242
+ type XAxisLabelFormatter = (datum: FoldBarDatum, index: number, data: FoldBarDatum[]) => string;
243
+ type XAxisBottomFormatter = (datum: FoldBarDatum, index: number, data: FoldBarDatum[]) => string | string[];
244
+ interface FoldBarXAxisTitleConfig {
245
+ text?: string;
246
+ /** Defaults to the horizontal center of the plot. */
247
+ x?: number;
248
+ /** Defaults to the row below the bottom labels. */
249
+ y?: number;
250
+ }
251
+ interface FoldBarXAxisConfig {
252
+ /** Formats the header-row category labels; defaults to the xField value. */
253
+ labelFormat?: XAxisLabelFormatter;
254
+ /**
255
+ * Optional semantic row below the plot (e.g. stage index + step conversion).
256
+ * Returning an array renders one line per entry. Reserves bottom space.
257
+ */
258
+ bottomLabels?: XAxisBottomFormatter;
259
+ /** Axis caption rendered below the bottom labels. Reserves one bottom row. */
260
+ title?: FoldBarXAxisTitleConfig;
261
+ /** Baseline under the bar bottoms (below the fade). Default false to keep the dissolving-paper look. */
262
+ showLine?: boolean;
263
+ /** Small marks under each column center. Default false. */
264
+ showTick?: boolean;
265
+ /** Vertical column dividers. Default true (previous always-on behavior). */
266
+ showGrid?: boolean;
267
+ }
268
+ type TooltipTone = 'n' | 'b' | 's';
269
+ interface TooltipPart {
270
+ text: string;
271
+ /** 'b' = bold ink, 's' = faded separator, 'n'/omitted = normal. */
272
+ tone?: TooltipTone;
273
+ }
274
+ type TooltipFormatter = (datum: FoldBarDatum, index: number, data: FoldBarDatum[]) => TooltipPart[];
275
+ interface FoldBarTooltipConfig {
276
+ enabled?: boolean;
277
+ formatter?: TooltipFormatter;
278
+ height?: number;
279
+ radius?: number;
280
+ paddingX?: number;
281
+ anchorRatio?: number;
282
+ offsetY?: number;
283
+ minY?: number;
284
+ /** Skip text measurement and use a fixed width (SSR / testing escape hatch). */
285
+ fixedWidth?: number;
286
+ }
287
+ interface FoldBarStateConfig {
288
+ /** Active column when idle. Defaults to the last column. */
289
+ defaultActive?: number;
290
+ }
291
+ interface FoldBarTitleConfig {
292
+ text?: string;
293
+ x?: number;
294
+ y?: number;
295
+ }
296
+ interface StripePatternStyle {
297
+ enabled: boolean;
298
+ size: number;
299
+ lineWidth: number;
300
+ lineColor: string;
301
+ lineOpacity: number;
302
+ rotation: number;
303
+ }
304
+ interface PillShadowStyle {
305
+ width: number;
306
+ height: number;
307
+ rx: number;
308
+ offsetY: number;
309
+ color: string;
310
+ opacity: number;
311
+ }
312
+ interface PillStyle {
313
+ enabled: boolean;
314
+ width: number;
315
+ height: number;
316
+ rx: number;
317
+ offsetY: number;
318
+ gradient: GradientStop[];
319
+ shadow: PillShadowStyle;
320
+ }
321
+ interface DropShadowStyle {
322
+ dx: number;
323
+ dy: number;
324
+ blur: number;
325
+ color: string;
326
+ opacity: number;
327
+ }
328
+ interface FoldBarStyleConfig {
329
+ stripePattern?: Partial<StripePatternStyle>;
330
+ /** The active stops paint the default-active bar; all other bars use normal. */
331
+ barGradient?: {
332
+ active?: GradientStop[];
333
+ normal?: GradientStop[];
334
+ };
335
+ foldGradient?: GradientStop[];
336
+ creaseGradient?: GradientStop[];
337
+ washTop?: number;
338
+ washGradient?: GradientStop[];
339
+ /** Renders the active-column wash backdrop. Default true. */
340
+ washEnabled?: boolean;
341
+ pill?: Partial<Omit<PillStyle, 'shadow'>> & {
342
+ shadow?: Partial<PillShadowStyle>;
343
+ };
344
+ shadow?: Partial<DropShadowStyle>;
345
+ /** `enabled: false` removes the dissolving baseline mask. Default true. */
346
+ fadeMask?: Partial<{
347
+ start: number;
348
+ end: number;
349
+ enabled: boolean;
350
+ }>;
351
+ labelY?: number;
352
+ numberY?: number;
353
+ /** Nudge of the label and value away from the bar's horizontal center. */
354
+ labelXOffset?: number;
355
+ }
356
+ /** Preset name ('light' | 'dark' | registered), an inline pack, or a legacy tokens partial. */
357
+ type ThemeRef = string | ThemePack | DeepPartialTokens;
358
+ interface FoldBarChartConfig extends BaseConfig {
359
+ data: FoldBarDatum[];
360
+ xField?: string;
361
+ yField?: string;
362
+ /** Formats bar header values and feeds the default tooltip formatter. */
363
+ valueFormat?: (value: number) => string;
364
+ ariaLabel?: string;
365
+ padding?: Partial<Padding>;
366
+ stair?: Partial<{
367
+ bottomOffset: number;
368
+ topOffset: number;
369
+ }>;
370
+ scale?: FoldBarScaleConfig;
371
+ fold?: FoldBarFoldConfig;
372
+ axis?: FoldBarAxisConfig;
373
+ xAxis?: FoldBarXAxisConfig;
374
+ tooltip?: FoldBarTooltipConfig;
375
+ state?: FoldBarStateConfig;
376
+ title?: FoldBarTitleConfig;
377
+ style?: FoldBarStyleConfig;
378
+ /** Preset name, inline theme pack, or legacy typography tokens; deep-merged over the defaults. */
379
+ theme?: ThemeRef;
380
+ }
381
+
382
+ /**
383
+ * Fold-paper funnel bar chart: gradient columns joined by folded flaps,
384
+ * striped idle state, wash highlight on the active column.
385
+ */
386
+ declare class FoldBarChart extends ChartBase<FoldBarChartConfig, ChartEventMap<FoldBarDatum>> {
387
+ private uid;
388
+ private model;
389
+ private rendered;
390
+ private interaction;
391
+ constructor(container: ContainerLike, config: FoldBarChartConfig);
392
+ /** Currently active (highlighted) column index. */
393
+ get activeIndex(): number;
394
+ /** Programmatically highlight a column. */
395
+ setActive(index: number): void;
396
+ protected renderChart(): void;
397
+ protected onDestroy(): void;
398
+ }
399
+
400
+ interface FoldBarOptions {
401
+ width: number;
402
+ height: number;
403
+ xField: string;
404
+ yField: string;
405
+ valueFormat: (value: number) => string;
406
+ ariaLabel: string;
407
+ padding: Padding;
408
+ stair: {
409
+ bottomOffset: number;
410
+ topOffset: number;
411
+ };
412
+ scale: {
413
+ exponent: number;
414
+ };
415
+ fold: {
416
+ run: number;
417
+ creaseColor: string;
418
+ creaseWidth: number;
419
+ };
420
+ axis: {
421
+ ticks: number[];
422
+ tickFormat: (value: number) => string;
423
+ /** Axis domain maximum; bars normalize against it so ticks map truthfully. */
424
+ domainMax: number;
425
+ };
426
+ xAxis: {
427
+ labelFormat: XAxisLabelFormatter;
428
+ bottomLabels?: XAxisBottomFormatter;
429
+ title: {
430
+ text: string;
431
+ x?: number;
432
+ y?: number;
433
+ };
434
+ showLine: boolean;
435
+ showTick: boolean;
436
+ showGrid: boolean;
437
+ };
438
+ tooltip: {
439
+ enabled: boolean;
440
+ formatter: TooltipFormatter;
441
+ height: number;
442
+ radius: number;
443
+ paddingX: number;
444
+ anchorRatio: number;
445
+ offsetY: number;
446
+ minY: number;
447
+ fixedWidth?: number;
448
+ };
449
+ state: {
450
+ defaultActive: number;
451
+ };
452
+ title: {
453
+ text: string;
454
+ x: number;
455
+ y: number;
456
+ };
457
+ style: ResolvedFoldBarStyle;
458
+ tokens: FoldBarThemeTokens;
459
+ }
460
+ /** Default header value formatter, matching the prototype's `65.2k` labels. */
461
+ declare const defaultValueFormat: (value: number) => string;
462
+ /** Neutral default tooltip: category label plus formatted value. */
463
+ declare function defaultTooltipFormatter(datum: FoldBarDatum): TooltipPart[];
464
+ interface NiceScale {
465
+ /** Nice axis maximum; bars normalize against it. */
466
+ axisMax: number;
467
+ step: number;
468
+ /** Nice tick values in descending order (topmost first), zero excluded. */
469
+ ticks: number[];
470
+ }
471
+ /** d3-style nice tick generation: step = multiplier × 10^power, keeping at most targetCount top ticks. */
472
+ declare function niceScale(maxValue: number, targetCount?: number): NiceScale;
473
+ interface FoldBarModel {
474
+ data: FoldBarDatum[];
475
+ labels: string[];
476
+ values: number[];
477
+ layout: FoldBarLayout;
478
+ bars: BarGeometry[];
479
+ flaps: (FlapGeometry | null)[];
480
+ /** Fade band that dissolves bar bottoms; derived from plot.bottom unless user-overridden. */
481
+ fade: {
482
+ start: number;
483
+ end: number;
484
+ };
485
+ options: FoldBarOptions;
486
+ }
487
+
488
+ interface ScaleOptions {
489
+ domain: [number, number];
490
+ range: [number, number];
491
+ }
492
+ /** Maps values from domain to range linearly. A degenerate domain maps everything to range[0]. */
493
+ declare function createLinearScale({ domain: [d0, d1], range: [r0, r1], }: ScaleOptions): (value: number) => number;
494
+
495
+ interface PowerScaleOptions extends ScaleOptions {
496
+ /** Power applied to the normalized value. 1 behaves exactly like a linear scale. */
497
+ exponent?: number;
498
+ }
499
+ /**
500
+ * Maps values from domain to range through t^exponent, where t is the normalized
501
+ * value clamped to [0, +inf). exponent < 1 emphasizes large values, > 1 compresses them.
502
+ */
503
+ declare function createPowerScale({ domain: [d0, d1], range: [r0, r1], exponent, }: PowerScaleOptions): (value: number) => number;
504
+
505
+ interface BandScale {
506
+ /** Full width of one band, including padding. */
507
+ step: number;
508
+ /** Usable width inside a band. */
509
+ bandwidth: number;
510
+ /** Leading edge of the band at index. */
511
+ position: (index: number) => number;
512
+ /** Center of the band at index. */
513
+ center: (index: number) => number;
514
+ }
515
+ /** Splits range into count equal bands. paddingRatio is the fraction of each step left empty. */
516
+ declare function createBandScale(count: number, range: [number, number], paddingRatio?: number): BandScale;
517
+
518
+ declare const VERSION = "0.1.0";
519
+
520
+ export { type BandScale, type BarGeometry, type BaseConfig, ChartBase, type ChartEventMap, type ColumnEventPayload, type ContainerLike, type DeepPartialTokens, type DownloadOptions, type ExportOptions, type FlapGeometry, type FoldBarAxisConfig, FoldBarChart, type FoldBarChartConfig, type FoldBarDatum, type FoldBarFoldConfig, type FoldBarLayout, type FoldBarModel, type FoldBarOptions, type FoldBarScaleConfig, type FoldBarStateConfig, type FoldBarStyleConfig, type FoldBarThemeTokens, type FoldBarTitleConfig, type FoldBarTooltipConfig, type FoldBarXAxisConfig, type FoldBarXAxisTitleConfig, type NiceScale, type Padding, type PillGeometry, type PlotRect, type PowerScaleOptions, type RectGeometry, type ResolvedFoldBarStyle, type ScaleOptions, type ThemeFormats, type ThemePack, type ThemeRef, type TooltipFormatter, type TooltipPart, type TooltipTone, VERSION, type XAxisBottomFormatter, type XAxisLabelFormatter, createBandScale, createLinearScale, createPowerScale, defaultTooltipFormatter, defaultValueFormat, getTheme, isThemePack, niceScale, registerTheme };