@spatika/react 1.4.0 → 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.
- package/AGENTS.md +6 -3
- package/README.md +1 -1
- package/dist/composites/EventCalendar.js +3 -3
- package/dist/composites/GlassCard.d.ts +1 -1
- package/dist/composites/RichTextEditor.d.ts +1 -4
- package/dist/composites/RichTextEditor.d.ts.map +1 -1
- package/dist/composites/RichTextEditor.js +12 -19
- package/dist/composites/SurfaceCard.d.ts +1 -1
- package/dist/composites/Tag.d.ts +2 -2
- package/dist/index.d.ts +8 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -11
- package/dist/lib/breakpoints.d.ts +17 -0
- package/dist/lib/breakpoints.d.ts.map +1 -0
- package/dist/lib/breakpoints.js +23 -0
- package/dist/lib/create-theme.d.ts +162 -0
- package/dist/lib/create-theme.d.ts.map +1 -0
- package/dist/lib/create-theme.js +138 -0
- package/dist/lib/scheduler.js +2 -2
- package/dist/lib/themes.d.ts +17 -7
- package/dist/lib/themes.d.ts.map +1 -1
- package/dist/lib/themes.js +22 -8
- package/dist/lib/use-media-query.d.ts +9 -0
- package/dist/lib/use-media-query.d.ts.map +1 -1
- package/dist/lib/use-media-query.js +28 -1
- package/dist/primitives/Alert.d.ts +1 -1
- package/dist/primitives/Badge.d.ts +2 -2
- package/dist/primitives/Button.d.ts +2 -2
- package/dist/primitives/Container.d.ts +2 -2
- package/dist/primitives/Fab.d.ts +4 -4
- package/dist/primitives/Grid.d.ts +2 -1
- package/dist/primitives/Grid.d.ts.map +1 -1
- package/dist/primitives/Grid.js +10 -2
- package/dist/primitives/IconButton.d.ts +2 -2
- package/dist/primitives/ToggleButton.d.ts +1 -1
- package/dist/theme/SpatikaThemeProvider.d.ts +4 -5
- package/dist/theme/SpatikaThemeProvider.d.ts.map +1 -1
- package/dist/theme/SpatikaThemeProvider.js +28 -13
- package/package.json +4 -2
- package/skills/spatika-ui/SKILL.md +25 -6
- package/src/composites/EventCalendar.test.tsx +293 -0
- package/src/composites/EventCalendar.tsx +3 -3
- package/src/composites/RichTextEditor.test.tsx +51 -0
- package/src/composites/RichTextEditor.tsx +20 -84
- package/src/composites/chart-ui.test.tsx +21 -0
- package/src/composites/scheduler.test.tsx +0 -258
- package/src/index.test.ts +6 -0
- package/src/index.ts +138 -72
- package/src/lib/breakpoints.test.ts +29 -0
- package/src/lib/breakpoints.ts +28 -0
- package/src/lib/create-theme.test.ts +79 -0
- package/src/lib/create-theme.ts +249 -0
- package/src/lib/scheduler.test.ts +10 -0
- package/src/lib/scheduler.ts +2 -2
- package/src/lib/themes.test.ts +17 -0
- package/src/lib/themes.ts +43 -12
- package/src/lib/use-media-query.test.tsx +80 -0
- package/src/lib/use-media-query.ts +35 -1
- package/src/primitives/Grid.test.tsx +55 -0
- package/src/primitives/Grid.tsx +13 -3
- package/src/primitives/mui-more.test.tsx +17 -0
- package/src/theme/SpatikaThemeProvider.test.tsx +38 -0
- package/src/theme/SpatikaThemeProvider.tsx +43 -15
- package/src/composites/ChartDataGrid.test.tsx +0 -57
- package/src/composites/ChartDataGrid.tsx +0 -196
- package/src/composites/MapChart.test.tsx +0 -39
- package/src/composites/MapChart.tsx +0 -130
- package/src/composites/ScatterWebGL.test.tsx +0 -25
- package/src/composites/ScatterWebGL.tsx +0 -79
- package/src/composites/cartesian-charts.test.tsx +0 -136
- package/src/composites/cartesian-charts.tsx +0 -1355
- package/src/composites/chart-composition.test.tsx +0 -68
- package/src/composites/chart-composition.tsx +0 -1039
- package/src/composites/chart-interaction.ts +0 -136
- package/src/composites/chart-ui.tsx +0 -336
- package/src/composites/charts-3d.test.tsx +0 -25
- package/src/composites/charts-3d.tsx +0 -318
- package/src/composites/charts.test.tsx +0 -254
- package/src/composites/flow-charts.test.tsx +0 -98
- package/src/composites/flow-charts.tsx +0 -641
- package/src/composites/radial-charts.test.tsx +0 -89
- package/src/composites/radial-charts.tsx +0 -643
- package/src/lib/chart-export.test.ts +0 -20
- package/src/lib/chart-export.ts +0 -99
- package/src/lib/charts-platform.test.ts +0 -93
- package/src/lib/charts.test.ts +0 -132
- package/src/lib/charts.ts +0 -1021
- package/src/lib/geo.test.ts +0 -42
- package/src/lib/geo.ts +0 -138
- package/src/lib/iso.test.ts +0 -22
- package/src/lib/iso.ts +0 -102
- package/src/lib/webgl-scatter.test.ts +0 -36
- package/src/lib/webgl-scatter.ts +0 -230
|
@@ -1,267 +1,9 @@
|
|
|
1
1
|
import { render, screen } from "@testing-library/react";
|
|
2
2
|
import userEvent from "@testing-library/user-event";
|
|
3
3
|
import { describe, expect, it, vi } from "vitest";
|
|
4
|
-
import { EventCalendar } from "./EventCalendar";
|
|
5
4
|
import { EventTimeline } from "./EventTimeline";
|
|
6
5
|
import type { SchedulerEvent, SchedulerResource } from "../lib/scheduler";
|
|
7
6
|
|
|
8
|
-
const resources: SchedulerResource[] = [
|
|
9
|
-
{ id: "work", title: "Work", color: "violet" },
|
|
10
|
-
{ id: "health", title: "Health", color: "teal" },
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
const events: SchedulerEvent[] = [
|
|
14
|
-
{
|
|
15
|
-
id: "run",
|
|
16
|
-
title: "Morning Run",
|
|
17
|
-
start: "2026-08-03T07:00:00",
|
|
18
|
-
end: "2026-08-03T07:45:00",
|
|
19
|
-
resourceId: "health",
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
id: "bday",
|
|
23
|
-
title: "Alice's Birthday",
|
|
24
|
-
start: "2026-08-06",
|
|
25
|
-
end: "2026-08-08",
|
|
26
|
-
allDay: true,
|
|
27
|
-
resourceId: "work",
|
|
28
|
-
color: "rose",
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
id: "review",
|
|
32
|
-
title: "Design Review",
|
|
33
|
-
start: "2026-08-09T14:00:00",
|
|
34
|
-
end: "2026-08-09T16:00:00",
|
|
35
|
-
resourceId: "work",
|
|
36
|
-
},
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
describe("EventCalendar", () => {
|
|
40
|
-
it("renders the month heading, weekday labels, and events", () => {
|
|
41
|
-
render(
|
|
42
|
-
<EventCalendar
|
|
43
|
-
defaultDate={new Date(2026, 7, 15)}
|
|
44
|
-
events={events}
|
|
45
|
-
resources={resources}
|
|
46
|
-
locale="en-US"
|
|
47
|
-
/>,
|
|
48
|
-
);
|
|
49
|
-
expect(screen.getByRole("heading", { name: /August 2026/i })).toBeInTheDocument();
|
|
50
|
-
expect(screen.getByText(/Sun/)).toBeInTheDocument();
|
|
51
|
-
expect(screen.getByText("Morning Run")).toBeInTheDocument();
|
|
52
|
-
expect(screen.getByText("Alice's Birthday")).toBeInTheDocument();
|
|
53
|
-
expect(screen.getByText("Work")).toBeInTheDocument();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("jumps to today from the toolbar", async () => {
|
|
57
|
-
const user = userEvent.setup();
|
|
58
|
-
const onDateChange = vi.fn();
|
|
59
|
-
render(
|
|
60
|
-
<EventCalendar
|
|
61
|
-
defaultDate={new Date(2025, 0, 1)}
|
|
62
|
-
onDateChange={onDateChange}
|
|
63
|
-
events={events}
|
|
64
|
-
/>,
|
|
65
|
-
);
|
|
66
|
-
await user.click(screen.getByRole("button", { name: "Today" }));
|
|
67
|
-
expect(onDateChange).toHaveBeenCalled();
|
|
68
|
-
const next = onDateChange.mock.calls[0][0] as Date;
|
|
69
|
-
const now = new Date();
|
|
70
|
-
expect(next.getFullYear()).toBe(now.getFullYear());
|
|
71
|
-
expect(next.getMonth()).toBe(now.getMonth());
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("fires onEventClick for a timed event", async () => {
|
|
75
|
-
const user = userEvent.setup();
|
|
76
|
-
const onEventClick = vi.fn();
|
|
77
|
-
render(
|
|
78
|
-
<EventCalendar
|
|
79
|
-
defaultDate={new Date(2026, 7, 15)}
|
|
80
|
-
events={events}
|
|
81
|
-
resources={resources}
|
|
82
|
-
locale="en-US"
|
|
83
|
-
onEventClick={onEventClick}
|
|
84
|
-
/>,
|
|
85
|
-
);
|
|
86
|
-
await user.click(screen.getByText("Morning Run"));
|
|
87
|
-
expect(onEventClick).toHaveBeenCalledWith(expect.objectContaining({ id: "run" }));
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("switches to week view from the menu", async () => {
|
|
91
|
-
const user = userEvent.setup();
|
|
92
|
-
render(
|
|
93
|
-
<EventCalendar defaultDate={new Date(2026, 7, 15)} events={events} locale="en-US" />,
|
|
94
|
-
);
|
|
95
|
-
await user.click(screen.getByRole("button", { name: /month/i }));
|
|
96
|
-
await user.click(screen.getByRole("menuitem", { name: "Week" }));
|
|
97
|
-
expect(screen.getByRole("heading", { name: /2026/ })).toBeInTheDocument();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it("lists events in agenda view", () => {
|
|
101
|
-
render(
|
|
102
|
-
<EventCalendar
|
|
103
|
-
defaultView="agenda"
|
|
104
|
-
defaultDate={new Date(2026, 7, 3)}
|
|
105
|
-
events={events}
|
|
106
|
-
locale="en-US"
|
|
107
|
-
/>,
|
|
108
|
-
);
|
|
109
|
-
expect(screen.getByRole("heading", { name: /Aug 3/ })).toBeInTheDocument();
|
|
110
|
-
expect(screen.getAllByText("No events").length).toBeGreaterThan(0);
|
|
111
|
-
expect(screen.getByText("Morning Run")).toBeInTheDocument();
|
|
112
|
-
expect(screen.getAllByText("Alice's Birthday").length).toBeGreaterThan(0);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it("opens the editor and saves title changes", async () => {
|
|
116
|
-
const user = userEvent.setup();
|
|
117
|
-
const onEventChange = vi.fn();
|
|
118
|
-
render(
|
|
119
|
-
<EventCalendar
|
|
120
|
-
defaultDate={new Date(2026, 7, 15)}
|
|
121
|
-
events={events}
|
|
122
|
-
resources={resources}
|
|
123
|
-
locale="en-US"
|
|
124
|
-
onEventChange={onEventChange}
|
|
125
|
-
/>,
|
|
126
|
-
);
|
|
127
|
-
await user.click(screen.getByText("Morning Run"));
|
|
128
|
-
const title = screen.getByRole("textbox", { name: /title/i });
|
|
129
|
-
await user.clear(title);
|
|
130
|
-
await user.type(title, "Jog");
|
|
131
|
-
await user.click(screen.getByRole("button", { name: "Save" }));
|
|
132
|
-
expect(onEventChange).toHaveBeenCalledWith(
|
|
133
|
-
expect.objectContaining({ id: "run" }),
|
|
134
|
-
expect.objectContaining({ title: "Jog" }),
|
|
135
|
-
);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it("creates an event from a day slot", async () => {
|
|
139
|
-
const user = userEvent.setup();
|
|
140
|
-
const onEventCreate = vi.fn();
|
|
141
|
-
render(
|
|
142
|
-
<EventCalendar
|
|
143
|
-
defaultDate={new Date(2026, 7, 15)}
|
|
144
|
-
events={events}
|
|
145
|
-
locale="en-US"
|
|
146
|
-
onEventCreate={onEventCreate}
|
|
147
|
-
/>,
|
|
148
|
-
);
|
|
149
|
-
await user.click(screen.getByRole("button", { name: "15" }));
|
|
150
|
-
expect(screen.getByRole("heading", { name: "New event" })).toBeInTheDocument();
|
|
151
|
-
await user.type(screen.getByRole("textbox", { name: /title/i }), "Focus time");
|
|
152
|
-
await user.click(screen.getByRole("button", { name: "Save" }));
|
|
153
|
-
expect(onEventCreate).toHaveBeenCalledWith(expect.objectContaining({ title: "Focus time" }));
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it("skips the built-in editor when showEventEditor is false", async () => {
|
|
157
|
-
const user = userEvent.setup();
|
|
158
|
-
const onEventClick = vi.fn();
|
|
159
|
-
const onSlotClick = vi.fn();
|
|
160
|
-
render(
|
|
161
|
-
<EventCalendar
|
|
162
|
-
defaultDate={new Date(2026, 7, 15)}
|
|
163
|
-
events={events}
|
|
164
|
-
resources={resources}
|
|
165
|
-
locale="en-US"
|
|
166
|
-
showEventEditor={false}
|
|
167
|
-
onEventClick={onEventClick}
|
|
168
|
-
onSlotClick={onSlotClick}
|
|
169
|
-
/>,
|
|
170
|
-
);
|
|
171
|
-
await user.click(screen.getByText("Morning Run"));
|
|
172
|
-
expect(onEventClick).toHaveBeenCalledWith(expect.objectContaining({ id: "run" }));
|
|
173
|
-
expect(screen.queryByRole("heading", { name: /event/i })).not.toBeInTheDocument();
|
|
174
|
-
|
|
175
|
-
await user.click(screen.getByRole("button", { name: "15" }));
|
|
176
|
-
expect(onSlotClick).toHaveBeenCalled();
|
|
177
|
-
expect(screen.queryByRole("heading", { name: "New event" })).not.toBeInTheDocument();
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it("renders custom event chips and toolbar", async () => {
|
|
181
|
-
const user = userEvent.setup();
|
|
182
|
-
const onDateChange = vi.fn();
|
|
183
|
-
render(
|
|
184
|
-
<EventCalendar
|
|
185
|
-
defaultDate={new Date(2026, 7, 15)}
|
|
186
|
-
events={events}
|
|
187
|
-
resources={resources}
|
|
188
|
-
locale="en-US"
|
|
189
|
-
showEventEditor={false}
|
|
190
|
-
showPreferences={false}
|
|
191
|
-
toolbarTrailing={<button type="button">Jump year</button>}
|
|
192
|
-
renderEvent={(event) => <span>★ {event.title}</span>}
|
|
193
|
-
renderToolbar={({ title, onToday }) => (
|
|
194
|
-
<div>
|
|
195
|
-
<p>{title}</p>
|
|
196
|
-
<button type="button" onClick={onToday}>
|
|
197
|
-
Jump today
|
|
198
|
-
</button>
|
|
199
|
-
</div>
|
|
200
|
-
)}
|
|
201
|
-
onDateChange={onDateChange}
|
|
202
|
-
/>,
|
|
203
|
-
);
|
|
204
|
-
expect(screen.getByText("★ Morning Run")).toBeInTheDocument();
|
|
205
|
-
expect(screen.queryByRole("button", { name: "Preferences" })).not.toBeInTheDocument();
|
|
206
|
-
expect(screen.queryByRole("button", { name: "Jump year" })).not.toBeInTheDocument();
|
|
207
|
-
await user.click(screen.getByRole("button", { name: "Jump today" }));
|
|
208
|
-
expect(onDateChange).toHaveBeenCalled();
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
it("keeps toolbarTrailing on the default toolbar", () => {
|
|
212
|
-
render(
|
|
213
|
-
<EventCalendar
|
|
214
|
-
defaultDate={new Date(2026, 7, 15)}
|
|
215
|
-
events={events}
|
|
216
|
-
locale="en-US"
|
|
217
|
-
showPreferences={false}
|
|
218
|
-
toolbarTrailing={<button type="button">Jump year</button>}
|
|
219
|
-
/>,
|
|
220
|
-
);
|
|
221
|
-
expect(screen.getByRole("button", { name: "Jump year" })).toBeInTheDocument();
|
|
222
|
-
expect(screen.getByRole("heading", { name: /August 2026/i })).toBeInTheDocument();
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it("renders a compact toolbar with equal month and year jumps", () => {
|
|
226
|
-
render(
|
|
227
|
-
<EventCalendar
|
|
228
|
-
defaultDate={new Date(2026, 7, 15)}
|
|
229
|
-
events={events}
|
|
230
|
-
locale="en-US"
|
|
231
|
-
showPreferences={false}
|
|
232
|
-
toolbarDensity="compact"
|
|
233
|
-
showDateJump
|
|
234
|
-
/>,
|
|
235
|
-
);
|
|
236
|
-
expect(document.querySelector('[data-density="compact"]')).toBeTruthy();
|
|
237
|
-
expect(screen.getByLabelText("Month")).toHaveAttribute("data-size", "sm");
|
|
238
|
-
expect(screen.getByLabelText("Year")).toHaveAttribute("data-size", "sm");
|
|
239
|
-
expect(screen.getByLabelText("Month")).toHaveValue("7");
|
|
240
|
-
expect(screen.getByLabelText("Year")).toHaveValue("2026");
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
it("reports the visible range for week view", () => {
|
|
244
|
-
const onVisibleRangeChange = vi.fn();
|
|
245
|
-
render(
|
|
246
|
-
<EventCalendar
|
|
247
|
-
defaultDate={new Date(2026, 7, 15)}
|
|
248
|
-
defaultView="week"
|
|
249
|
-
locale="en-US"
|
|
250
|
-
onVisibleRangeChange={onVisibleRangeChange}
|
|
251
|
-
/>,
|
|
252
|
-
);
|
|
253
|
-
expect(onVisibleRangeChange).toHaveBeenCalled();
|
|
254
|
-
const range = onVisibleRangeChange.mock.calls[0][0] as {
|
|
255
|
-
view: string;
|
|
256
|
-
start: Date;
|
|
257
|
-
end: Date;
|
|
258
|
-
};
|
|
259
|
-
expect(range.view).toBe("week");
|
|
260
|
-
expect(range.start.getDay()).toBe(0);
|
|
261
|
-
expect(range.end.getTime() - range.start.getTime()).toBe(7 * 86_400_000);
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
|
|
265
7
|
describe("EventTimeline", () => {
|
|
266
8
|
const timelineEvents: SchedulerEvent[] = [
|
|
267
9
|
{
|
package/src/index.test.ts
CHANGED
|
@@ -9,7 +9,9 @@ import {
|
|
|
9
9
|
MapChart,
|
|
10
10
|
SchedulerDateJump,
|
|
11
11
|
SchedulerToolbar,
|
|
12
|
+
BREAKPOINTS,
|
|
12
13
|
calendarVisibleRange,
|
|
14
|
+
createTheme,
|
|
13
15
|
mercator,
|
|
14
16
|
} from "./index";
|
|
15
17
|
|
|
@@ -26,5 +28,9 @@ describe("@spatika/react public exports", () => {
|
|
|
26
28
|
expect(SchedulerDateJump).toBeTypeOf("function");
|
|
27
29
|
expect(calendarVisibleRange).toBeTypeOf("function");
|
|
28
30
|
expect(mercator([0, 0])[0]).toBeCloseTo(0.5);
|
|
31
|
+
expect(BREAKPOINTS.md).toBe(768);
|
|
32
|
+
expect(createTheme({ id: "brand", palette: { primary: "#7c3aed" } }).vars["--primary"]).toBe(
|
|
33
|
+
"#7c3aed",
|
|
34
|
+
);
|
|
29
35
|
});
|
|
30
36
|
});
|
package/src/index.ts
CHANGED
|
@@ -57,8 +57,33 @@ export {
|
|
|
57
57
|
applyTheme,
|
|
58
58
|
isDarkTheme,
|
|
59
59
|
isThemeId,
|
|
60
|
+
type ApplyThemeCustom,
|
|
61
|
+
type BuiltinThemeId,
|
|
60
62
|
type ThemeId,
|
|
61
63
|
} from "./lib/themes";
|
|
64
|
+
export {
|
|
65
|
+
createTheme,
|
|
66
|
+
themeToCss,
|
|
67
|
+
injectCustomThemeStyles,
|
|
68
|
+
findCustomTheme,
|
|
69
|
+
PALETTE_CSS_VARS,
|
|
70
|
+
GLASS_CSS_VARS,
|
|
71
|
+
SHAPE_CSS_VARS,
|
|
72
|
+
type CreateThemeOptions,
|
|
73
|
+
type SpatikaTheme,
|
|
74
|
+
type ThemePalette,
|
|
75
|
+
type ThemeGlass,
|
|
76
|
+
type ThemeShape,
|
|
77
|
+
type ThemeTypography,
|
|
78
|
+
} from "./lib/create-theme";
|
|
79
|
+
export {
|
|
80
|
+
BREAKPOINTS,
|
|
81
|
+
BREAKPOINT_KEYS,
|
|
82
|
+
breakpointUp,
|
|
83
|
+
breakpointDown,
|
|
84
|
+
breakpointBetween,
|
|
85
|
+
type Breakpoint,
|
|
86
|
+
} from "./lib/breakpoints";
|
|
62
87
|
export { getAvatarColor, getAvatarFallbackHue, getInitials } from "./lib/avatar-utils";
|
|
63
88
|
export {
|
|
64
89
|
COVER_PATTERN_KINDS,
|
|
@@ -79,7 +104,13 @@ export {
|
|
|
79
104
|
coverTitleClass,
|
|
80
105
|
} from "./lib/cover-chrome";
|
|
81
106
|
export { useCoverChromeBleed, type CoverChromeInk } from "./lib/use-cover-chrome-bleed";
|
|
82
|
-
export {
|
|
107
|
+
export {
|
|
108
|
+
useIsMobile,
|
|
109
|
+
useMediaQuery,
|
|
110
|
+
useBreakpoint,
|
|
111
|
+
useBreakpointUp,
|
|
112
|
+
useBreakpointDown,
|
|
113
|
+
} from "./lib/use-media-query";
|
|
83
114
|
export {
|
|
84
115
|
SpatikaThemeProvider,
|
|
85
116
|
useSpatikaTheme,
|
|
@@ -404,6 +435,36 @@ export {
|
|
|
404
435
|
type PhotoViewerItem,
|
|
405
436
|
} from "./composites/PhotoViewer";
|
|
406
437
|
export { RichTextEditor, type RichTextEditorProps } from "./composites/RichTextEditor";
|
|
438
|
+
export {
|
|
439
|
+
SpatikaEditor,
|
|
440
|
+
useSpatikaEditor,
|
|
441
|
+
buildSpatikaExtensions,
|
|
442
|
+
EditorToolbar,
|
|
443
|
+
EditorBubbleMenu,
|
|
444
|
+
ImageBubbleMenu,
|
|
445
|
+
SlashCommandMenu,
|
|
446
|
+
MentionMenu,
|
|
447
|
+
AiOverlay,
|
|
448
|
+
ToolbarButton,
|
|
449
|
+
createSlashCommandExtension,
|
|
450
|
+
defaultSlashCommands,
|
|
451
|
+
createMentionExtension,
|
|
452
|
+
ResizableImage,
|
|
453
|
+
createAiActionExtension,
|
|
454
|
+
} from "@spatika/editor";
|
|
455
|
+
export type {
|
|
456
|
+
SpatikaEditorProps,
|
|
457
|
+
SpatikaEditorHandle,
|
|
458
|
+
SpatikaEditorToolbarConfig,
|
|
459
|
+
SlashCommandItem,
|
|
460
|
+
MentionContact,
|
|
461
|
+
AiActionDefinition,
|
|
462
|
+
PlaceholderConfig,
|
|
463
|
+
UseSpatikaEditorOptions,
|
|
464
|
+
SlashCommandStorage,
|
|
465
|
+
MentionStorage,
|
|
466
|
+
ImageAlign,
|
|
467
|
+
} from "@spatika/editor";
|
|
407
468
|
export { HeaderIconButton, type HeaderIconButtonProps } from "./composites/HeaderIconButton";
|
|
408
469
|
export {
|
|
409
470
|
QuickFilterRail,
|
|
@@ -529,26 +590,25 @@ export {
|
|
|
529
590
|
CHART_COLOR_VARS,
|
|
530
591
|
chartColor,
|
|
531
592
|
formatChartNumber,
|
|
593
|
+
formatAxisNumber,
|
|
594
|
+
resolveChartRadius,
|
|
595
|
+
categoryLabelGutter,
|
|
596
|
+
fitCategoryLabel,
|
|
532
597
|
seriesDataFromDataset,
|
|
533
598
|
axisDataFromDataset,
|
|
534
599
|
clampZoom,
|
|
535
600
|
DEFAULT_ZOOM,
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
HighlightScope,
|
|
545
|
-
SankeyLink,
|
|
546
|
-
SankeyNode,
|
|
547
|
-
TreeNode,
|
|
548
|
-
} from "./lib/charts";
|
|
549
|
-
export { serializeChartSvg, exportChart, downloadChartSvg, downloadChartPng } from "./lib/chart-export";
|
|
550
|
-
export {
|
|
601
|
+
stackSeries,
|
|
602
|
+
errorBarRange,
|
|
603
|
+
pieLabelLine,
|
|
604
|
+
seriesHasPlottableData,
|
|
605
|
+
serializeChartSvg,
|
|
606
|
+
exportChart,
|
|
607
|
+
downloadChartSvg,
|
|
608
|
+
downloadChartPng,
|
|
551
609
|
ChartContainer,
|
|
610
|
+
ComposedChart,
|
|
611
|
+
ResponsiveContainer,
|
|
552
612
|
ChartSurface,
|
|
553
613
|
ChartsGrid,
|
|
554
614
|
ChartsXAxis,
|
|
@@ -556,28 +616,16 @@ export {
|
|
|
556
616
|
ChartsLegend,
|
|
557
617
|
ChartsToolbar,
|
|
558
618
|
ChartsBrush,
|
|
619
|
+
ChartsCursor,
|
|
559
620
|
ChartsReferenceLine,
|
|
621
|
+
ChartsReferenceArea,
|
|
622
|
+
ChartsReferenceDot,
|
|
623
|
+
ChartsErrorBar,
|
|
560
624
|
BarPlot,
|
|
561
625
|
LinePlot,
|
|
562
626
|
AreaPlot,
|
|
563
627
|
ScatterPlot,
|
|
564
628
|
useChartContext,
|
|
565
|
-
} from "./composites/chart-composition";
|
|
566
|
-
export type {
|
|
567
|
-
ChartContainerProps,
|
|
568
|
-
ComposedSeries,
|
|
569
|
-
ComposedSeriesType,
|
|
570
|
-
HighlightedItem,
|
|
571
|
-
} from "./composites/chart-composition";
|
|
572
|
-
export type {
|
|
573
|
-
ChartHover,
|
|
574
|
-
ChartItemEvent,
|
|
575
|
-
ChartMarkRenderContext,
|
|
576
|
-
ChartReferenceLine,
|
|
577
|
-
ChartTooltipItem,
|
|
578
|
-
ChartTooltipRenderer,
|
|
579
|
-
} from "./composites/chart-interaction";
|
|
580
|
-
export {
|
|
581
629
|
AreaChart,
|
|
582
630
|
BarChart,
|
|
583
631
|
BoxPlotChart,
|
|
@@ -590,8 +638,60 @@ export {
|
|
|
590
638
|
ScatterChart,
|
|
591
639
|
SparkLineChart,
|
|
592
640
|
WaterfallChart,
|
|
593
|
-
|
|
641
|
+
Gauge,
|
|
642
|
+
LinearGauge,
|
|
643
|
+
PieChart,
|
|
644
|
+
PolarLineChart,
|
|
645
|
+
RadarChart,
|
|
646
|
+
RadialBarChart,
|
|
647
|
+
RadialLineChart,
|
|
648
|
+
ChordChart,
|
|
649
|
+
FunnelChart,
|
|
650
|
+
Heatmap,
|
|
651
|
+
PyramidChart,
|
|
652
|
+
SankeyChart,
|
|
653
|
+
SunburstChart,
|
|
654
|
+
Treemap,
|
|
655
|
+
MapChart,
|
|
656
|
+
BarChart3D,
|
|
657
|
+
PieChart3D,
|
|
658
|
+
ChartDataGrid,
|
|
659
|
+
renderChartCell,
|
|
660
|
+
mercator,
|
|
661
|
+
equirectangular,
|
|
662
|
+
geoPath,
|
|
663
|
+
fitFeatures,
|
|
664
|
+
featureId,
|
|
665
|
+
} from "@spatika/charts";
|
|
594
666
|
export type {
|
|
667
|
+
ChartAxisConfig,
|
|
668
|
+
ChartCurve,
|
|
669
|
+
ChartDataset,
|
|
670
|
+
ChartErrorValue,
|
|
671
|
+
ChartInteraction,
|
|
672
|
+
ChartLegendPosition,
|
|
673
|
+
ChartMargin,
|
|
674
|
+
ChartRadius,
|
|
675
|
+
ChartZoom,
|
|
676
|
+
HighlightScope,
|
|
677
|
+
SankeyLink,
|
|
678
|
+
SankeyNode,
|
|
679
|
+
StackOffset,
|
|
680
|
+
TreeNode,
|
|
681
|
+
ChartContainerProps,
|
|
682
|
+
ComposedSeries,
|
|
683
|
+
ComposedSeriesType,
|
|
684
|
+
HighlightedItem,
|
|
685
|
+
ResponsiveContainerProps,
|
|
686
|
+
ChartHover,
|
|
687
|
+
ChartItemEvent,
|
|
688
|
+
ChartMarkRenderContext,
|
|
689
|
+
ChartReferenceArea,
|
|
690
|
+
ChartReferenceDot,
|
|
691
|
+
ChartReferenceLine,
|
|
692
|
+
ChartTooltipItem,
|
|
693
|
+
ChartTooltipRenderer,
|
|
694
|
+
ChartTooltipTrigger,
|
|
595
695
|
BarChartProps,
|
|
596
696
|
BoxPlotChartProps,
|
|
597
697
|
CandleDatum,
|
|
@@ -608,17 +708,6 @@ export type {
|
|
|
608
708
|
ScatterSeries,
|
|
609
709
|
SparkLineChartProps,
|
|
610
710
|
WaterfallChartProps,
|
|
611
|
-
} from "./composites/cartesian-charts";
|
|
612
|
-
export {
|
|
613
|
-
Gauge,
|
|
614
|
-
LinearGauge,
|
|
615
|
-
PieChart,
|
|
616
|
-
PolarLineChart,
|
|
617
|
-
RadarChart,
|
|
618
|
-
RadialBarChart,
|
|
619
|
-
RadialLineChart,
|
|
620
|
-
} from "./composites/radial-charts";
|
|
621
|
-
export type {
|
|
622
711
|
GaugeProps,
|
|
623
712
|
GaugeSection,
|
|
624
713
|
LinearGaugeProps,
|
|
@@ -629,17 +718,6 @@ export type {
|
|
|
629
718
|
RadarSeries,
|
|
630
719
|
RadialBarChartProps,
|
|
631
720
|
RadialLineChartProps,
|
|
632
|
-
} from "./composites/radial-charts";
|
|
633
|
-
export {
|
|
634
|
-
ChordChart,
|
|
635
|
-
FunnelChart,
|
|
636
|
-
Heatmap,
|
|
637
|
-
PyramidChart,
|
|
638
|
-
SankeyChart,
|
|
639
|
-
SunburstChart,
|
|
640
|
-
Treemap,
|
|
641
|
-
} from "./composites/flow-charts";
|
|
642
|
-
export type {
|
|
643
721
|
ChordChartProps,
|
|
644
722
|
FunnelChartProps,
|
|
645
723
|
FunnelDatum,
|
|
@@ -650,28 +728,16 @@ export type {
|
|
|
650
728
|
SankeyChartProps,
|
|
651
729
|
SunburstChartProps,
|
|
652
730
|
TreemapProps,
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
export type { BarChart3DProps, PieChart3DProps } from "./composites/charts-3d";
|
|
658
|
-
export { ChartDataGrid, renderChartCell } from "./composites/ChartDataGrid";
|
|
659
|
-
export type {
|
|
731
|
+
MapChartProps,
|
|
732
|
+
MapShapeDatum,
|
|
733
|
+
BarChart3DProps,
|
|
734
|
+
PieChart3DProps,
|
|
660
735
|
ChartDataGridProps,
|
|
661
736
|
ChartDataGridRow,
|
|
662
737
|
ChartGridColumn,
|
|
663
738
|
ChartGridColumnType,
|
|
664
|
-
} from "./composites/ChartDataGrid";
|
|
665
|
-
export {
|
|
666
|
-
mercator,
|
|
667
|
-
equirectangular,
|
|
668
|
-
geoPath,
|
|
669
|
-
fitFeatures,
|
|
670
|
-
featureId,
|
|
671
|
-
} from "./lib/geo";
|
|
672
|
-
export type {
|
|
673
739
|
GeoJsonFeature,
|
|
674
740
|
GeoJsonFeatureCollection,
|
|
675
741
|
GeoJsonGeometry,
|
|
676
742
|
GeoProjectionKind,
|
|
677
|
-
} from "
|
|
743
|
+
} from "@spatika/charts";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
BREAKPOINTS,
|
|
4
|
+
BREAKPOINT_KEYS,
|
|
5
|
+
breakpointBetween,
|
|
6
|
+
breakpointDown,
|
|
7
|
+
breakpointUp,
|
|
8
|
+
} from "./breakpoints";
|
|
9
|
+
|
|
10
|
+
describe("breakpoints", () => {
|
|
11
|
+
it("matches Tailwind viewport widths", () => {
|
|
12
|
+
expect(BREAKPOINTS).toEqual({ xs: 0, sm: 640, md: 768, lg: 1024, xl: 1280 });
|
|
13
|
+
expect(BREAKPOINT_KEYS).toEqual(["xs", "sm", "md", "lg", "xl"]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("builds min-width and max-width queries", () => {
|
|
17
|
+
expect(breakpointUp("xs")).toBe("(min-width: 0px)");
|
|
18
|
+
expect(breakpointUp("md")).toBe("(min-width: 768px)");
|
|
19
|
+
expect(breakpointDown("md")).toBe("(max-width: 767px)");
|
|
20
|
+
expect(breakpointDown("xl")).toBe("(max-width: 1279px)");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("builds an inclusive range", () => {
|
|
24
|
+
expect(breakpointBetween("sm", "lg")).toBe(
|
|
25
|
+
"(min-width: 640px) and (max-width: 1023px)",
|
|
26
|
+
);
|
|
27
|
+
expect(breakpointBetween("md")).toBe("(min-width: 768px)");
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Viewport widths (px) that match Tailwind and Spatika `Grid` / `Container`. */
|
|
2
|
+
export const BREAKPOINTS = {
|
|
3
|
+
xs: 0,
|
|
4
|
+
sm: 640,
|
|
5
|
+
md: 768,
|
|
6
|
+
lg: 1024,
|
|
7
|
+
xl: 1280,
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
export type Breakpoint = keyof typeof BREAKPOINTS;
|
|
11
|
+
|
|
12
|
+
export const BREAKPOINT_KEYS = ["xs", "sm", "md", "lg", "xl"] as const satisfies readonly Breakpoint[];
|
|
13
|
+
|
|
14
|
+
/** `(min-width: Npx)` — inclusive start of a breakpoint. `xs` is always true. */
|
|
15
|
+
export function breakpointUp(key: Breakpoint): string {
|
|
16
|
+
return `(min-width: ${BREAKPOINTS[key]}px)`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** `(max-width: N-1px)` — viewports strictly below a breakpoint. */
|
|
20
|
+
export function breakpointDown(key: Exclude<Breakpoint, "xs">): string {
|
|
21
|
+
return `(max-width: ${BREAKPOINTS[key] - 1}px)`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Inclusive range between two breakpoints. `end` omitted means no upper bound. */
|
|
25
|
+
export function breakpointBetween(start: Breakpoint, end?: Exclude<Breakpoint, "xs">): string {
|
|
26
|
+
if (!end) return breakpointUp(start);
|
|
27
|
+
return `${breakpointUp(start)} and ${breakpointDown(end)}`;
|
|
28
|
+
}
|