@konce-pt/react 0.18.0 → 0.18.1
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/charts/chart.js +38 -16
- package/dist/charts/llms.txt +10 -0
- package/dist/charts-entry/public-api.d.ts +1 -1
- package/package.json +14 -14
package/dist/charts/chart.js
CHANGED
|
@@ -1,12 +1,35 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useId, useRef, useState } from 'react';
|
|
4
|
-
import { KptChartMotion, areaPath, axisBase, bandPath, bandScale, barLayout, chartScale, chartAccessibleName, chartDataTable, dataScale, deltaKind, domainScale, formatNumber, linePath, linearScale, pieSlices, plotArea, polarSlices, polarToCartesian, polygonPath, radarGrid, radarPoints, radialArea, sameChartShape, scaleRows, seriesColor, significantDelta, stackSeries, } from '@konce-pt/chart';
|
|
4
|
+
import { KptChartMotion, areaPath, axisBase, axisLabelIndices, bandPath, bandScale, barLayout, chartScale, chartAccessibleName, chartDataTable, clampLabel, dataScale, deltaKind, domainScale, estimateLabelWidth, formatNumber, linePath, linearScale, pieSlices, plotArea, polarSlices, polarToCartesian, polygonPath, radarGrid, radarPoints, radialArea, sameChartShape, scaleRows, seriesColor, significantDelta, stackSeries, } from '@konce-pt/chart';
|
|
5
5
|
import { cn } from "../internal/cn.js";
|
|
6
6
|
import { useKptMotion } from "../motion/motion-context.js";
|
|
7
7
|
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
8
8
|
import { KptChartLegend } from "./chart-legend.js";
|
|
9
9
|
import { KptChartTooltip } from "./chart-tooltip.js";
|
|
10
|
+
/** Wysokość linii etykiety kategorii na osi pionowej (słupki poziome) - jednostki viewBoxa. */
|
|
11
|
+
const CATEGORY_LINE = 12;
|
|
12
|
+
/**
|
|
13
|
+
* Etykiety osi poziomej: wszystkie, jeśli się mieszczą, inaczej równy podział 9/5/3/2
|
|
14
|
+
* (`axisLabelIndices`). Pełna nazwa każdej kategorii zostaje w pigułce prowadnicy i w dymku.
|
|
15
|
+
*/
|
|
16
|
+
function bottomLabels(labels, centers, y, width) {
|
|
17
|
+
const sizes = labels.map((l) => estimateLabelWidth(l));
|
|
18
|
+
const shown = new Set(axisLabelIndices(centers, sizes));
|
|
19
|
+
return labels.map((text, i) => ({
|
|
20
|
+
at: centers[i] ?? 0,
|
|
21
|
+
x: clampLabel(centers[i] ?? 0, sizes[i] ?? 0, 0, width),
|
|
22
|
+
y,
|
|
23
|
+
text,
|
|
24
|
+
anchor: 'middle',
|
|
25
|
+
visible: shown.has(i),
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
/** Etykiety osi pionowej (słupki poziome): ten sam podział, rozmiarem jest wysokość linii. */
|
|
29
|
+
function sideLabels(labels, centers, x) {
|
|
30
|
+
const shown = new Set(axisLabelIndices(centers, centers.map(() => CATEGORY_LINE), 2));
|
|
31
|
+
return labels.map((text, i) => ({ at: centers[i] ?? 0, x, y: (centers[i] ?? 0) + 3, text, anchor: 'end', visible: shown.has(i) }));
|
|
32
|
+
}
|
|
10
33
|
const VERTICAL_INSETS = { top: 12, right: 16, bottom: 28, left: 46 };
|
|
11
34
|
const HORIZONTAL_INSETS = { top: 12, right: 16, bottom: 28, left: 76 };
|
|
12
35
|
/** Szerokość pasma smugi światła (jednostki viewBoxa) - połowa po każdej stronie czoła fali. */
|
|
@@ -234,12 +257,8 @@ export function KptChart({ config, width = 600, height = 360, locale, dictionary
|
|
|
234
257
|
text: formatNumber(t),
|
|
235
258
|
anchor: 'end',
|
|
236
259
|
}));
|
|
237
|
-
const catLabels = view.labels.map((
|
|
238
|
-
|
|
239
|
-
y: plot.y + plot.height + 18,
|
|
240
|
-
text: label,
|
|
241
|
-
anchor: 'middle',
|
|
242
|
-
}));
|
|
260
|
+
const catLabels = bottomLabels(view.labels, view.labels.map((_, i) => xAt(i)), plot.y + plot.height + 18, width);
|
|
261
|
+
const catTicks = view.labels.map((_, i) => ({ x: xAt(i), y: plot.y + plot.height }));
|
|
243
262
|
const series = active.map(({ s, i }, k) => ({
|
|
244
263
|
key: `ser:${s.name}`,
|
|
245
264
|
name: s.name,
|
|
@@ -257,14 +276,16 @@ export function KptChart({ config, width = 600, height = 360, locale, dictionary
|
|
|
257
276
|
: [];
|
|
258
277
|
const crosshairCat = config.crosshair && activeIndex !== null ? catLabels[activeIndex] : undefined;
|
|
259
278
|
// Prowadnica i pigułka jadą razem z dymkiem.
|
|
260
|
-
const crossX = crosshairCat ? (frame.tip?.x ?? crosshairCat.
|
|
279
|
+
const crossX = crosshairCat ? (frame.tip?.x ?? crosshairCat.at) : 0;
|
|
261
280
|
const pillWidth = crosshairCat ? Math.max(28, crosshairCat.text.length * 7 + 16) : 0;
|
|
281
|
+
// Pigułka przy skrajnej kategorii przesuwa się do środka zamiast wyjść poza viewBox.
|
|
282
|
+
const pillX = crosshairCat ? clampLabel(crossX, pillWidth, 0, width) : 0;
|
|
262
283
|
/** Najbliższa kategoria w całym obszarze wykresu: wiersze wszystkich serii, dymek nad najwyższym punktem. */
|
|
263
284
|
const onMove = (event) => {
|
|
264
285
|
const p = svgPoint(event);
|
|
265
286
|
if (!p || !series.length)
|
|
266
287
|
return;
|
|
267
|
-
const idx = nearestIndex(catLabels.map((l) => l.
|
|
288
|
+
const idx = nearestIndex(catLabels.map((l) => l.at), p.x);
|
|
268
289
|
if (keepTip(idx))
|
|
269
290
|
return;
|
|
270
291
|
const hits = series.map((s) => ({ s, pt: s.points[idx] })).filter((e) => !!e.pt);
|
|
@@ -278,7 +299,7 @@ export function KptChart({ config, width = 600, height = 360, locale, dictionary
|
|
|
278
299
|
if (moved && tipMotion())
|
|
279
300
|
setRipple({ id: ++rippleId.current, x: top.pt.x, y: top.pt.y, color: top.s.color });
|
|
280
301
|
};
|
|
281
|
-
return (_jsxs(_Fragment, { children: [_jsx("g", { className: "kpt-chart__grid", children: grid.map((g, i) => (_jsx("line", { className: "kpt-chart__gridline", x1: g.x1, y1: g.y1, x2: g.x2, y2: g.y2 }, i))) }), crosshairCat ? (_jsx("line", { className: "kpt-chart__crosshair", x1: crossX, y1: plot.y, x2: crossX, y2: plot.y + plot.height })) : null, _jsx("g", { className: "kpt-chart__axis", children: [...valueLabels, ...catLabels].map((l, i) => (_jsx("text", { x: l.x, y: l.y, textAnchor: l.anchor, children: l.text }, i))) }), crosshairCat ? (_jsxs("g", { className: "kpt-chart__cat-active", children: [_jsx("rect", { x:
|
|
302
|
+
return (_jsxs(_Fragment, { children: [_jsx("g", { className: "kpt-chart__grid", children: grid.map((g, i) => (_jsx("line", { className: "kpt-chart__gridline", x1: g.x1, y1: g.y1, x2: g.x2, y2: g.y2 }, i))) }), crosshairCat ? (_jsx("line", { className: "kpt-chart__crosshair", x1: crossX, y1: plot.y, x2: crossX, y2: plot.y + plot.height })) : null, _jsx("g", { className: "kpt-chart__axis", children: [...valueLabels, ...catLabels.filter((l) => l.visible)].map((l, i) => (_jsx("text", { x: l.x, y: l.y, textAnchor: l.anchor, children: l.text }, i))) }), _jsx("g", { className: "kpt-chart__cat-ticks", "aria-hidden": "true", children: catTicks.map((tk, i) => (_jsx("circle", { className: cn('kpt-chart__cat-tick', activeIndex === i && 'kpt-chart__cat-tick--active'), r: 2, cx: tk.x, cy: tk.y }, i))) }), crosshairCat ? (_jsxs("g", { className: "kpt-chart__cat-active", children: [_jsx("rect", { x: pillX - pillWidth / 2, y: crosshairCat.y - 13, width: pillWidth, height: 18, rx: 9 }), _jsx("text", { x: pillX, y: crosshairCat.y, textAnchor: "middle", children: crosshairCat.text })] })) : null, ghostState
|
|
282
303
|
? series.map((s) => {
|
|
283
304
|
const prev = ghostState.prev[s.i] ?? [];
|
|
284
305
|
const next = ghostState.next[s.i] ?? [];
|
|
@@ -332,9 +353,10 @@ export function KptChart({ config, width = 600, height = 360, locale, dictionary
|
|
|
332
353
|
text: formatNumber(t.value),
|
|
333
354
|
anchor: 'middle',
|
|
334
355
|
}));
|
|
356
|
+
const centers = view.labels.map((_, i) => cat.center(i));
|
|
335
357
|
const catLabels = vertical
|
|
336
|
-
? view.labels
|
|
337
|
-
: view.labels
|
|
358
|
+
? bottomLabels(view.labels, centers, plot.y + plot.height + 18, width)
|
|
359
|
+
: sideLabels(view.labels, centers, plot.x - 8);
|
|
338
360
|
const bars = layout.bars.map((b, order) => ({
|
|
339
361
|
b,
|
|
340
362
|
order,
|
|
@@ -371,7 +393,7 @@ export function KptChart({ config, width = 600, height = 360, locale, dictionary
|
|
|
371
393
|
const p = svgPoint(event);
|
|
372
394
|
if (!p)
|
|
373
395
|
return;
|
|
374
|
-
const idx = nearestIndex(catLabels.map((l) =>
|
|
396
|
+
const idx = nearestIndex(catLabels.map((l) => l.at), vertical ? p.x : p.y);
|
|
375
397
|
if (keepTip(idx))
|
|
376
398
|
return;
|
|
377
399
|
const group = bars.filter((e) => e.b.categoryIndex === idx);
|
|
@@ -379,11 +401,11 @@ export function KptChart({ config, width = 600, height = 360, locale, dictionary
|
|
|
379
401
|
if (!group.length || !center)
|
|
380
402
|
return;
|
|
381
403
|
const label = config.labels[idx] ?? '';
|
|
382
|
-
const x = vertical ? center.
|
|
383
|
-
const y = vertical ? Math.min(...group.map((e) => e.tipY)) : center.
|
|
404
|
+
const x = vertical ? center.at : Math.max(...group.map((e) => e.tipX));
|
|
405
|
+
const y = vertical ? Math.min(...group.map((e) => e.tipY)) : center.at;
|
|
384
406
|
openTip(x, y, label, group.map((e) => row(e.name, label, e.b.value, e.color)), idx);
|
|
385
407
|
};
|
|
386
|
-
return (_jsxs(_Fragment, { children: [_jsx("g", { className: "kpt-chart__grid", children: grid.map((g, i) => (_jsx("line", { className: "kpt-chart__gridline", x1: g.x1, y1: g.y1, x2: g.x2, y2: g.y2 }, i))) }), _jsx("g", { className: "kpt-chart__axis", children: [...valueLabels, ...catLabels].map((l, i) => (_jsx("text", { x: l.x, y: l.y, textAnchor: l.anchor, children: l.text }, i))) }), ghostBars.length ? (_jsx("g", { className: "kpt-chart__ghost", "aria-hidden": "true", children: ghostBars.map((g) => (_jsx("path", { className: "kpt-chart__ghost-bar", d: g.path }, g.key))) })) : null, _jsx("g", { className: "kpt-chart__bars", "data-orientation": orientation, children: bars.map((e) => (_jsx("path", { className: cn('kpt-chart__bar', dim(e.key) && 'kpt-chart__series--dim'), d: e.b.path, style: { fill: e.color, ['--kpt-chart-i']: e.order } }, `${e.key}#${e.order}`))) }), ghostBars.length ? (_jsx("g", { className: "kpt-chart__ghost", "aria-hidden": "true", children: ghostBars.map((g) => (_jsx("rect", { className: "kpt-chart__delta-bar", "data-kind": g.kind, rx: 2, ...g.delta }, g.key))) })) : null, sheen
|
|
408
|
+
return (_jsxs(_Fragment, { children: [_jsx("g", { className: "kpt-chart__grid", children: grid.map((g, i) => (_jsx("line", { className: "kpt-chart__gridline", x1: g.x1, y1: g.y1, x2: g.x2, y2: g.y2 }, i))) }), _jsx("g", { className: "kpt-chart__axis", children: [...valueLabels, ...catLabels.filter((l) => l.visible)].map((l, i) => (_jsx("text", { x: l.x, y: l.y, textAnchor: l.anchor, children: l.text }, i))) }), ghostBars.length ? (_jsx("g", { className: "kpt-chart__ghost", "aria-hidden": "true", children: ghostBars.map((g) => (_jsx("path", { className: "kpt-chart__ghost-bar", d: g.path }, g.key))) })) : null, _jsx("g", { className: "kpt-chart__bars", "data-orientation": orientation, children: bars.map((e) => (_jsx("path", { className: cn('kpt-chart__bar', dim(e.key) && 'kpt-chart__series--dim'), d: e.b.path, style: { fill: e.color, ['--kpt-chart-i']: e.order } }, `${e.key}#${e.order}`))) }), ghostBars.length ? (_jsx("g", { className: "kpt-chart__ghost", "aria-hidden": "true", children: ghostBars.map((g) => (_jsx("rect", { className: "kpt-chart__delta-bar", "data-kind": g.kind, rx: 2, ...g.delta }, g.key))) })) : null, sheen
|
|
387
409
|
? bars.map((e) => (_jsx("path", { className: "kpt-chart__sheen-bar", d: e.b.path, fill: `url(#${sheenId})`, style: { opacity: sheen.opacity * 0.7 }, "aria-hidden": "true" }, `${e.key}#${e.order}`)))
|
|
388
410
|
: null, _jsx("rect", { className: "kpt-chart__hover", x: plot.x, y: plot.y, width: plot.width, height: plot.height, onPointerMove: onMove, onPointerLeave: hideTip })] }));
|
|
389
411
|
})();
|
package/dist/charts/llms.txt
CHANGED
|
@@ -32,6 +32,16 @@ takes, because both read it from `@konce-pt/chart`.
|
|
|
32
32
|
`area`). The axis covers the totals; the tooltip shows the values of the series, not the totals
|
|
33
33
|
- The rules live in `@konce-pt/chart`: `axisScale`, `chartScale`, `stackSeries`, `bandPath` (tested)
|
|
34
34
|
|
|
35
|
+
## Category axis (line, bar)
|
|
36
|
+
- When the category labels do not fit, the axis shows an even subset instead of overlapping text: all of
|
|
37
|
+
them if they fit, otherwise the densest split that fits - 9 labels (eighths of the axis), 5 (first, 1/4,
|
|
38
|
+
middle, 3/4, last), 3, and finally the two ends only. Horizontal bars apply the same rule to the rows
|
|
39
|
+
- The choice is made in viewBox units, so it follows `width`, not the on-screen size; the outer labels and the
|
|
40
|
+
crosshair pill are shifted inward so they never leave the chart
|
|
41
|
+
- A line chart marks every category with a small dot on the axis; the active one grows on hover. The full
|
|
42
|
+
name of any category stays in the crosshair pill and the tooltip
|
|
43
|
+
- The rules live in `@konce-pt/chart`: `axisLabelIndices`, `estimateLabelWidth`, `clampLabel` (tested)
|
|
44
|
+
|
|
35
45
|
## The geometry lives in a package
|
|
36
46
|
Scales, paths, bar layout and arcs come from `@konce-pt/chart` - pure functions with `node --test`
|
|
37
47
|
coverage, shared with the Angular port. The component only turns them into SVG elements; there is
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { KptChart } from '../charts/chart.tsx';
|
|
2
2
|
export type { KptChartProps } from '../charts/chart.tsx';
|
|
3
|
-
export type { KptChartConfig, KptChartSeries, KptChartType, KptLineInterpolation, KptBarOrientation, KptLegendOptions, KptLegendPosition, KptLegendTitle, KptAlign, KptPointStyle, KptTitleOptions, KptTooltipOptions, KptTooltipContext, KptAnimationOptions, KptFont, KptPadding, } from '@konce-pt/chart';
|
|
3
|
+
export type { KptChartConfig, KptChartSeries, KptChartType, KptLineInterpolation, KptBarOrientation, KptLegendOptions, KptLegendPosition, KptLegendTitle, KptAlign, KptPointStyle, KptTitleOptions, KptTooltipOptions, KptTooltipContext, KptAnimationOptions, KptValueAxisOptions, KptFont, KptPadding, } from '@konce-pt/chart';
|
|
4
4
|
export { KPT_CHART_PALETTE, seriesColor, linePath, areaPath, pieSlices, polarSlices, barLayout, radarGrid, radarPoints, niceScale, } from '@konce-pt/chart';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konce-pt/react",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"description": "Open-source React 19 component library on the Koncept UI design system - the same kpt-* CSS layer and --kpt-* tokens as the Angular port. Zero runtime dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "konce.pt",
|
|
@@ -65,19 +65,19 @@
|
|
|
65
65
|
"leaflet": "^1.9.0"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@konce-pt/backdrop": "0.18.
|
|
69
|
-
"@konce-pt/
|
|
70
|
-
"@konce-pt/
|
|
71
|
-
"@konce-pt/
|
|
72
|
-
"@konce-pt/
|
|
73
|
-
"@konce-pt/
|
|
74
|
-
"@konce-pt/
|
|
75
|
-
"@konce-pt/
|
|
76
|
-
"@konce-pt/
|
|
77
|
-
"@konce-pt/
|
|
78
|
-
"@konce-pt/
|
|
79
|
-
"@konce-pt/
|
|
80
|
-
"@konce-pt/
|
|
68
|
+
"@konce-pt/backdrop": "0.18.1",
|
|
69
|
+
"@konce-pt/icons": "0.18.1",
|
|
70
|
+
"@konce-pt/chart": "0.18.1",
|
|
71
|
+
"@konce-pt/roadmap": "0.18.1",
|
|
72
|
+
"@konce-pt/mention": "0.18.1",
|
|
73
|
+
"@konce-pt/speech": "0.18.1",
|
|
74
|
+
"@konce-pt/motion": "0.18.1",
|
|
75
|
+
"@konce-pt/i18n": "0.18.1",
|
|
76
|
+
"@konce-pt/map": "0.18.1",
|
|
77
|
+
"@konce-pt/chat": "0.18.1",
|
|
78
|
+
"@konce-pt/tokens": "0.18.1",
|
|
79
|
+
"@konce-pt/datetime": "0.18.1",
|
|
80
|
+
"@konce-pt/table": "0.18.1"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
83
|
"@types/react": "^19.2.0",
|