@spatika/react 1.3.1 → 1.5.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.
Files changed (127) hide show
  1. package/AGENTS.md +6 -3
  2. package/README.md +1 -1
  3. package/dist/composites/EventCalendar.d.ts +13 -2
  4. package/dist/composites/EventCalendar.d.ts.map +1 -1
  5. package/dist/composites/EventCalendar.js +13 -27
  6. package/dist/composites/GlassCard.d.ts +1 -1
  7. package/dist/composites/RichTextEditor.d.ts +1 -4
  8. package/dist/composites/RichTextEditor.d.ts.map +1 -1
  9. package/dist/composites/RichTextEditor.js +12 -19
  10. package/dist/composites/SurfaceCard.d.ts +1 -1
  11. package/dist/composites/Tag.d.ts +2 -2
  12. package/dist/composites/cartesian-charts.d.ts +12 -2
  13. package/dist/composites/cartesian-charts.d.ts.map +1 -1
  14. package/dist/composites/cartesian-charts.js +27 -13
  15. package/dist/composites/chart-composition.d.ts +19 -1
  16. package/dist/composites/chart-composition.d.ts.map +1 -1
  17. package/dist/composites/chart-composition.js +124 -62
  18. package/dist/composites/chart-interaction.d.ts +81 -0
  19. package/dist/composites/chart-interaction.d.ts.map +1 -0
  20. package/dist/composites/chart-interaction.js +56 -0
  21. package/dist/composites/chart-ui.d.ts +8 -13
  22. package/dist/composites/chart-ui.d.ts.map +1 -1
  23. package/dist/composites/chart-ui.js +9 -6
  24. package/dist/composites/flow-charts.d.ts +6 -1
  25. package/dist/composites/flow-charts.d.ts.map +1 -1
  26. package/dist/composites/flow-charts.js +28 -14
  27. package/dist/composites/radial-charts.d.ts +11 -1
  28. package/dist/composites/radial-charts.d.ts.map +1 -1
  29. package/dist/composites/radial-charts.js +33 -14
  30. package/dist/composites/scheduler-ui.d.ts +14 -1
  31. package/dist/composites/scheduler-ui.d.ts.map +1 -1
  32. package/dist/composites/scheduler-ui.js +23 -2
  33. package/dist/index.d.ts +14 -26
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +8 -14
  36. package/dist/lib/breakpoints.d.ts +17 -0
  37. package/dist/lib/breakpoints.d.ts.map +1 -0
  38. package/dist/lib/breakpoints.js +23 -0
  39. package/dist/lib/chips.d.ts +3 -0
  40. package/dist/lib/chips.d.ts.map +1 -1
  41. package/dist/lib/chips.js +10 -0
  42. package/dist/lib/create-theme.d.ts +162 -0
  43. package/dist/lib/create-theme.d.ts.map +1 -0
  44. package/dist/lib/create-theme.js +138 -0
  45. package/dist/lib/scheduler.d.ts +12 -0
  46. package/dist/lib/scheduler.d.ts.map +1 -1
  47. package/dist/lib/scheduler.js +24 -2
  48. package/dist/lib/themes.d.ts +17 -7
  49. package/dist/lib/themes.d.ts.map +1 -1
  50. package/dist/lib/themes.js +22 -8
  51. package/dist/lib/use-media-query.d.ts +9 -0
  52. package/dist/lib/use-media-query.d.ts.map +1 -1
  53. package/dist/lib/use-media-query.js +28 -1
  54. package/dist/primitives/Alert.d.ts +1 -1
  55. package/dist/primitives/Badge.d.ts +2 -2
  56. package/dist/primitives/Button.d.ts +2 -2
  57. package/dist/primitives/Container.d.ts +2 -2
  58. package/dist/primitives/Fab.d.ts +4 -4
  59. package/dist/primitives/Grid.d.ts +2 -1
  60. package/dist/primitives/Grid.d.ts.map +1 -1
  61. package/dist/primitives/Grid.js +10 -2
  62. package/dist/primitives/IconButton.d.ts +2 -2
  63. package/dist/primitives/NativeSelect.d.ts +10 -1
  64. package/dist/primitives/NativeSelect.d.ts.map +1 -1
  65. package/dist/primitives/NativeSelect.js +2 -2
  66. package/dist/primitives/ToggleButton.d.ts +1 -1
  67. package/dist/theme/SpatikaThemeProvider.d.ts +4 -5
  68. package/dist/theme/SpatikaThemeProvider.d.ts.map +1 -1
  69. package/dist/theme/SpatikaThemeProvider.js +28 -13
  70. package/package.json +4 -2
  71. package/skills/spatika-ui/SKILL.md +28 -5
  72. package/src/composites/EventCalendar.test.tsx +293 -0
  73. package/src/composites/EventCalendar.tsx +38 -27
  74. package/src/composites/RichTextEditor.test.tsx +51 -0
  75. package/src/composites/RichTextEditor.tsx +20 -84
  76. package/src/composites/chart-ui.test.tsx +21 -0
  77. package/src/composites/scheduler-ui.tsx +128 -26
  78. package/src/composites/scheduler.test.tsx +0 -219
  79. package/src/index.test.ts +10 -0
  80. package/src/index.ts +148 -65
  81. package/src/lib/breakpoints.test.ts +29 -0
  82. package/src/lib/breakpoints.ts +28 -0
  83. package/src/lib/chips.ts +16 -0
  84. package/src/lib/create-theme.test.ts +79 -0
  85. package/src/lib/create-theme.ts +249 -0
  86. package/src/lib/scheduler.test.ts +26 -0
  87. package/src/lib/scheduler.ts +36 -2
  88. package/src/lib/themes.test.ts +17 -0
  89. package/src/lib/themes.ts +43 -12
  90. package/src/lib/use-media-query.test.tsx +80 -0
  91. package/src/lib/use-media-query.ts +35 -1
  92. package/src/primitives/Grid.test.tsx +55 -0
  93. package/src/primitives/Grid.tsx +13 -3
  94. package/src/primitives/NativeSelect.test.tsx +28 -0
  95. package/src/primitives/NativeSelect.tsx +14 -4
  96. package/src/primitives/mui-more.test.tsx +17 -0
  97. package/src/theme/SpatikaThemeProvider.test.tsx +38 -0
  98. package/src/theme/SpatikaThemeProvider.tsx +43 -15
  99. package/src/composites/ChartDataGrid.test.tsx +0 -57
  100. package/src/composites/ChartDataGrid.tsx +0 -196
  101. package/src/composites/MapChart.test.tsx +0 -39
  102. package/src/composites/MapChart.tsx +0 -130
  103. package/src/composites/ScatterWebGL.test.tsx +0 -25
  104. package/src/composites/ScatterWebGL.tsx +0 -79
  105. package/src/composites/cartesian-charts.test.tsx +0 -52
  106. package/src/composites/cartesian-charts.tsx +0 -1287
  107. package/src/composites/chart-composition.test.tsx +0 -53
  108. package/src/composites/chart-composition.tsx +0 -898
  109. package/src/composites/chart-ui.tsx +0 -328
  110. package/src/composites/charts-3d.test.tsx +0 -25
  111. package/src/composites/charts-3d.tsx +0 -318
  112. package/src/composites/charts.test.tsx +0 -254
  113. package/src/composites/flow-charts.test.tsx +0 -79
  114. package/src/composites/flow-charts.tsx +0 -607
  115. package/src/composites/radial-charts.test.tsx +0 -74
  116. package/src/composites/radial-charts.tsx +0 -617
  117. package/src/lib/chart-export.test.ts +0 -20
  118. package/src/lib/chart-export.ts +0 -99
  119. package/src/lib/charts-platform.test.ts +0 -93
  120. package/src/lib/charts.test.ts +0 -132
  121. package/src/lib/charts.ts +0 -1021
  122. package/src/lib/geo.test.ts +0 -42
  123. package/src/lib/geo.ts +0 -138
  124. package/src/lib/iso.test.ts +0 -22
  125. package/src/lib/iso.ts +0 -102
  126. package/src/lib/webgl-scatter.test.ts +0 -36
  127. package/src/lib/webgl-scatter.ts +0 -230
@@ -1,130 +0,0 @@
1
- import { chartColor, formatChartNumber, type ChartMargin } from "../lib/charts";
2
- import {
3
- featureId,
4
- fitFeatures,
5
- geoPath,
6
- type GeoJsonFeatureCollection,
7
- type GeoProjectionKind,
8
- } from "../lib/geo";
9
- import { ChartFrame, useChartHover } from "./chart-ui";
10
-
11
- export type MapShapeDatum = {
12
- id: string | number;
13
- value: number;
14
- label?: string;
15
- color?: string;
16
- };
17
-
18
- export type MapChartProps = {
19
- geoData: GeoJsonFeatureCollection;
20
- series?: Array<{ data: MapShapeDatum[] }>;
21
- idProperty?: string;
22
- projection?: GeoProjectionKind;
23
- height?: number;
24
- width?: number;
25
- colors?: string[];
26
- hideLegend?: boolean;
27
- margin?: ChartMargin;
28
- className?: string;
29
- };
30
-
31
- export function MapChart({
32
- geoData,
33
- series,
34
- idProperty = "id",
35
- projection = "mercator",
36
- height = 280,
37
- width,
38
- colors,
39
- hideLegend,
40
- margin,
41
- className,
42
- }: MapChartProps) {
43
- const features = geoData.features ?? [];
44
- const data = series?.[0]?.data ?? [];
45
- const byId = new Map(data.map((item) => [String(item.id), item]));
46
- const values = data.map((item) => item.value);
47
- const min = values.length ? Math.min(...values) : 0;
48
- const max = values.length ? Math.max(...values) : 1;
49
- const { hover, setHover, clear } = useChartHover();
50
- const legend = hideLegend
51
- ? undefined
52
- : data.slice(0, 8).map((item, i) => ({
53
- id: String(item.id),
54
- label: item.label ?? String(item.id),
55
- color: item.color ?? choroplethFill(item.value, min, max, i, colors),
56
- }));
57
-
58
- return (
59
- <ChartFrame
60
- slot="map-chart"
61
- className={className}
62
- width={width}
63
- height={height}
64
- margin={margin ?? { top: 8, right: 8, bottom: 8, left: 8 }}
65
- legend={legend}
66
- hover={hover}
67
- aria-label="Map chart"
68
- >
69
- {({ width: w, height: h, m }) => {
70
- const pad = Math.min(m.left, m.right, m.top, m.bottom);
71
- const project = fitFeatures(features, w, h, pad, projection);
72
- return (
73
- <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`}>
74
- {features.map((feature, i) => {
75
- if (!feature.geometry) return null;
76
- const id = featureId(feature, idProperty) || String(i);
77
- const datum = byId.get(id);
78
- const label =
79
- datum?.label ??
80
- (feature.properties?.name != null ? String(feature.properties.name) : id);
81
- const fill = datum
82
- ? (datum.color ?? choroplethFill(datum.value, min, max, i, colors))
83
- : "color-mix(in srgb, var(--muted) 55%, transparent)";
84
- const d = geoPath(feature.geometry, project);
85
- if (!d) return null;
86
- return (
87
- <path
88
- key={id}
89
- d={d}
90
- fill={fill}
91
- className="spk-chart-map-region spk-chart-mark"
92
- onMouseEnter={(event) =>
93
- setHover({
94
- x: event.nativeEvent.offsetX,
95
- y: event.nativeEvent.offsetY,
96
- title: label,
97
- items: datum
98
- ? [
99
- {
100
- color: fill,
101
- label: label,
102
- value: formatChartNumber(datum.value),
103
- },
104
- ]
105
- : [{ color: fill, label: label, value: "—" }],
106
- })
107
- }
108
- onMouseLeave={clear}
109
- />
110
- );
111
- })}
112
- </svg>
113
- );
114
- }}
115
- </ChartFrame>
116
- );
117
- }
118
-
119
- function choroplethFill(
120
- value: number,
121
- min: number,
122
- max: number,
123
- index: number,
124
- colors?: string[],
125
- ): string {
126
- const t = max === min ? 0.6 : (value - min) / (max - min);
127
- const base = chartColor(index, colors);
128
- const mix = Math.round(28 + t * 72);
129
- return `color-mix(in srgb, ${base} ${mix}%, var(--muted))`;
130
- }
@@ -1,25 +0,0 @@
1
- import { render } from "@testing-library/react";
2
- import { describe, expect, it, vi } from "vitest";
3
- import { ScatterWebGLLayer } from "./ScatterWebGL";
4
-
5
- describe("ScatterWebGLLayer", () => {
6
- it("renders a canvas layer and reports when WebGL is unavailable", () => {
7
- const onUnavailable = vi.fn();
8
- const { container } = render(
9
- <ScatterWebGLLayer
10
- width={120}
11
- height={80}
12
- series={[{ data: [{ x: 1, y: 2 }] }]}
13
- meta={[{ id: "a", label: "A", color: "#2563eb" }]}
14
- hidden={new Set()}
15
- xAt={(value) => value}
16
- yAt={(value) => value}
17
- sizeAt={(z) => z}
18
- bubble={false}
19
- onUnavailable={onUnavailable}
20
- />,
21
- );
22
- expect(container.querySelector('[data-slot="scatter-webgl"]')).toBeTruthy();
23
- expect(onUnavailable).toHaveBeenCalled();
24
- });
25
- });
@@ -1,79 +0,0 @@
1
- import { useEffect, useRef } from "react";
2
- import { createScatterGL, destroyScatterGL, drawScatterGL, type ScatterGL } from "../lib/webgl-scatter";
3
- import type { ChartLegendItem } from "./chart-ui";
4
-
5
- type ScatterSeriesLike = {
6
- data: Array<{ x: number; y: number; z?: number }>;
7
- };
8
-
9
- export function ScatterWebGLLayer({
10
- width,
11
- height,
12
- series,
13
- meta,
14
- hidden,
15
- xAt,
16
- yAt,
17
- sizeAt,
18
- bubble,
19
- onUnavailable,
20
- }: {
21
- width: number;
22
- height: number;
23
- series: ScatterSeriesLike[];
24
- meta: ChartLegendItem[];
25
- hidden: Set<string>;
26
- xAt: (value: number) => number;
27
- yAt: (value: number) => number;
28
- sizeAt: (z: number) => number;
29
- bubble: boolean;
30
- onUnavailable?: () => void;
31
- }) {
32
- const canvasRef = useRef<HTMLCanvasElement>(null);
33
- const gpuRef = useRef<ScatterGL | null>(null);
34
-
35
- useEffect(() => {
36
- const canvas = canvasRef.current;
37
- if (!canvas) return;
38
- const gpu = createScatterGL(canvas);
39
- if (!gpu) {
40
- onUnavailable?.();
41
- return;
42
- }
43
- gpuRef.current = gpu;
44
- return () => {
45
- destroyScatterGL(gpu);
46
- gpuRef.current = null;
47
- };
48
- }, [onUnavailable]);
49
-
50
- useEffect(() => {
51
- const gpu = gpuRef.current;
52
- const canvas = canvasRef.current;
53
- if (!gpu || !canvas) return;
54
- const batches = series.flatMap((item, s) => {
55
- const info = meta[s]!;
56
- if (hidden.has(info.id)) return [];
57
- return [
58
- {
59
- color: info.color,
60
- positions: item.data.map((point) => ({
61
- x: xAt(point.x),
62
- y: yAt(point.y),
63
- size: bubble ? sizeAt(point.z ?? 1) * 2 : 9,
64
- })),
65
- },
66
- ];
67
- });
68
- drawScatterGL(gpu, canvas, width, height, batches);
69
- });
70
-
71
- return (
72
- <canvas
73
- ref={canvasRef}
74
- className="spk-chart-webgl"
75
- data-slot="scatter-webgl"
76
- aria-hidden
77
- />
78
- );
79
- }
@@ -1,52 +0,0 @@
1
- import { render, screen } from "@testing-library/react";
2
- import { describe, expect, it } from "vitest";
3
- import { AreaChart, BarChart, LineChart } from "./cartesian-charts";
4
-
5
- const months = ["Jan", "Feb", "Mar"];
6
-
7
- describe("cartesian-charts", () => {
8
- it("renders grouped bars for categorical series", () => {
9
- render(
10
- <BarChart
11
- width={360}
12
- height={220}
13
- xAxis={[{ data: months }]}
14
- series={[
15
- { label: "Views", data: [4, 3, 5] },
16
- { label: "Signups", data: [1, 2, 2] },
17
- ]}
18
- />,
19
- );
20
- expect(screen.getByRole("img", { name: /bar chart/i })).toBeInTheDocument();
21
- expect(document.querySelectorAll('[data-slot="bar-plot"] .spk-chart-mark').length).toBeGreaterThan(0);
22
- });
23
-
24
- it("renders line series from numeric data", () => {
25
- const { container } = render(
26
- <LineChart
27
- width={360}
28
- height={220}
29
- xAxis={[{ data: months }]}
30
- series={[{ label: "Revenue", data: [2, 4, 3] }]}
31
- />,
32
- );
33
- expect(container.querySelector('[data-slot="line-plot"] path')).toBeTruthy();
34
- });
35
-
36
- it("stacks area series so later layers sit on earlier totals", () => {
37
- const { container } = render(
38
- <AreaChart
39
- width={360}
40
- height={220}
41
- stacked
42
- xAxis={[{ data: months }]}
43
- series={[
44
- { label: "v1", data: [2, 3, 4] },
45
- { label: "v2", data: [1, 1, 2] },
46
- ]}
47
- />,
48
- );
49
- expect(container.querySelector('[data-slot="area-plot"]')).toBeTruthy();
50
- expect(container.querySelectorAll('[data-slot="area-plot"] path').length).toBeGreaterThanOrEqual(2);
51
- });
52
- });