@spatika/react 1.3.1 → 1.4.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/dist/composites/EventCalendar.d.ts +13 -2
- package/dist/composites/EventCalendar.d.ts.map +1 -1
- package/dist/composites/EventCalendar.js +10 -24
- package/dist/composites/cartesian-charts.d.ts +12 -2
- package/dist/composites/cartesian-charts.d.ts.map +1 -1
- package/dist/composites/cartesian-charts.js +27 -13
- package/dist/composites/chart-composition.d.ts +19 -1
- package/dist/composites/chart-composition.d.ts.map +1 -1
- package/dist/composites/chart-composition.js +124 -62
- package/dist/composites/chart-interaction.d.ts +81 -0
- package/dist/composites/chart-interaction.d.ts.map +1 -0
- package/dist/composites/chart-interaction.js +56 -0
- package/dist/composites/chart-ui.d.ts +8 -13
- package/dist/composites/chart-ui.d.ts.map +1 -1
- package/dist/composites/chart-ui.js +9 -6
- package/dist/composites/flow-charts.d.ts +6 -1
- package/dist/composites/flow-charts.d.ts.map +1 -1
- package/dist/composites/flow-charts.js +28 -14
- package/dist/composites/radial-charts.d.ts +11 -1
- package/dist/composites/radial-charts.d.ts.map +1 -1
- package/dist/composites/radial-charts.js +33 -14
- package/dist/composites/scheduler-ui.d.ts +14 -1
- package/dist/composites/scheduler-ui.d.ts.map +1 -1
- package/dist/composites/scheduler-ui.js +23 -2
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/lib/chips.d.ts +3 -0
- package/dist/lib/chips.d.ts.map +1 -1
- package/dist/lib/chips.js +10 -0
- package/dist/lib/scheduler.d.ts +12 -0
- package/dist/lib/scheduler.d.ts.map +1 -1
- package/dist/lib/scheduler.js +22 -0
- package/dist/primitives/NativeSelect.d.ts +10 -1
- package/dist/primitives/NativeSelect.d.ts.map +1 -1
- package/dist/primitives/NativeSelect.js +2 -2
- package/package.json +2 -2
- package/skills/spatika-ui/SKILL.md +4 -0
- package/src/composites/EventCalendar.tsx +35 -24
- package/src/composites/cartesian-charts.test.tsx +86 -2
- package/src/composites/cartesian-charts.tsx +84 -16
- package/src/composites/chart-composition.test.tsx +15 -0
- package/src/composites/chart-composition.tsx +229 -88
- package/src/composites/chart-interaction.ts +136 -0
- package/src/composites/chart-ui.tsx +35 -27
- package/src/composites/flow-charts.test.tsx +21 -2
- package/src/composites/flow-charts.tsx +59 -25
- package/src/composites/radial-charts.test.tsx +17 -2
- package/src/composites/radial-charts.tsx +38 -12
- package/src/composites/scheduler-ui.tsx +128 -26
- package/src/composites/scheduler.test.tsx +39 -0
- package/src/index.test.ts +4 -0
- package/src/index.ts +18 -1
- package/src/lib/chips.ts +16 -0
- package/src/lib/scheduler.test.ts +16 -0
- package/src/lib/scheduler.ts +34 -0
- package/src/primitives/NativeSelect.test.tsx +28 -0
- package/src/primitives/NativeSelect.tsx +14 -4
package/src/index.ts
CHANGED
|
@@ -37,7 +37,9 @@ export {
|
|
|
37
37
|
layoutToggleClass,
|
|
38
38
|
listRowToggleClass,
|
|
39
39
|
nativeSelectClass,
|
|
40
|
+
nativeSelectSizeClass,
|
|
40
41
|
} from "./lib/chips";
|
|
42
|
+
export type { NativeSelectSize } from "./lib/chips";
|
|
41
43
|
export {
|
|
42
44
|
duration,
|
|
43
45
|
transition,
|
|
@@ -209,7 +211,7 @@ export {
|
|
|
209
211
|
SelectTrigger,
|
|
210
212
|
SelectValue,
|
|
211
213
|
} from "./primitives/Select";
|
|
212
|
-
export { NativeSelect } from "./primitives/NativeSelect";
|
|
214
|
+
export { NativeSelect, type NativeSelectProps } from "./primitives/NativeSelect";
|
|
213
215
|
export { Spinner } from "./primitives/Spinner";
|
|
214
216
|
export { Alert, AlertTitle, AlertDescription, alertVariants } from "./primitives/Alert";
|
|
215
217
|
export { Kbd } from "./primitives/Kbd";
|
|
@@ -500,16 +502,22 @@ export {
|
|
|
500
502
|
} from "./composites/EventEditor";
|
|
501
503
|
export {
|
|
502
504
|
SchedulerToolbar,
|
|
505
|
+
SchedulerDateJump,
|
|
503
506
|
SchedulerPreferencesMenu,
|
|
504
507
|
CALENDAR_VIEW_LABEL,
|
|
505
508
|
type SchedulerToolbarProps,
|
|
509
|
+
type SchedulerToolbarDensity,
|
|
510
|
+
type SchedulerDateJumpProps,
|
|
506
511
|
} from "./composites/scheduler-ui";
|
|
507
512
|
export {
|
|
508
513
|
DEFAULT_SCHEDULER_PREFERENCES,
|
|
509
514
|
SCHEDULER_COLOR_TONES,
|
|
515
|
+
CALENDAR_AGENDA_DAYS,
|
|
516
|
+
calendarVisibleRange,
|
|
510
517
|
} from "./lib/scheduler";
|
|
511
518
|
export type {
|
|
512
519
|
CalendarView,
|
|
520
|
+
CalendarVisibleRange,
|
|
513
521
|
NormalizedEvent,
|
|
514
522
|
SchedulerColorTone,
|
|
515
523
|
SchedulerEvent,
|
|
@@ -548,6 +556,7 @@ export {
|
|
|
548
556
|
ChartsLegend,
|
|
549
557
|
ChartsToolbar,
|
|
550
558
|
ChartsBrush,
|
|
559
|
+
ChartsReferenceLine,
|
|
551
560
|
BarPlot,
|
|
552
561
|
LinePlot,
|
|
553
562
|
AreaPlot,
|
|
@@ -560,6 +569,14 @@ export type {
|
|
|
560
569
|
ComposedSeriesType,
|
|
561
570
|
HighlightedItem,
|
|
562
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";
|
|
563
580
|
export {
|
|
564
581
|
AreaChart,
|
|
565
582
|
BarChart,
|
package/src/lib/chips.ts
CHANGED
|
@@ -56,3 +56,19 @@ export const nativeSelectClass = cn(
|
|
|
56
56
|
"focus:outline-none focus:border-primary/40 focus:ring-2 focus:ring-primary/20",
|
|
57
57
|
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
58
58
|
);
|
|
59
|
+
|
|
60
|
+
export type NativeSelectSize = "sm" | "default" | "touch";
|
|
61
|
+
|
|
62
|
+
/** Size recipes for NativeSelect. `sm` is for toolbars (not full width). */
|
|
63
|
+
export function nativeSelectSizeClass(size: NativeSelectSize = "default") {
|
|
64
|
+
if (size === "sm") {
|
|
65
|
+
return cn(
|
|
66
|
+
nativeSelectClass,
|
|
67
|
+
"mt-0 h-8 min-h-8 w-auto rounded-full px-2 text-[11px] font-semibold",
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
if (size === "touch") {
|
|
71
|
+
return cn(nativeSelectClass, "mt-0 min-h-11");
|
|
72
|
+
}
|
|
73
|
+
return cn(nativeSelectClass, "mt-0");
|
|
74
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
addDays,
|
|
4
|
+
calendarVisibleRange,
|
|
5
|
+
CALENDAR_AGENDA_DAYS,
|
|
4
6
|
formatDateRange,
|
|
5
7
|
getMonthGrid,
|
|
6
8
|
getTimelineRange,
|
|
@@ -35,6 +37,20 @@ describe("scheduler dates", () => {
|
|
|
35
37
|
expect(grid[0].getMonth()).toBe(6);
|
|
36
38
|
});
|
|
37
39
|
|
|
40
|
+
it("reports the exclusive visible range for month, week, and agenda", () => {
|
|
41
|
+
const month = calendarVisibleRange("month", new Date(2026, 7, 15), 0);
|
|
42
|
+
expect(month.start.getDate()).toBe(26);
|
|
43
|
+
expect(month.start.getMonth()).toBe(6);
|
|
44
|
+
expect(month.end.getTime()).toBe(addDays(getMonthGrid(new Date(2026, 7, 15), 0)[41], 1).getTime());
|
|
45
|
+
|
|
46
|
+
const week = calendarVisibleRange("week", new Date(2026, 7, 15), 0);
|
|
47
|
+
expect(week.start.getDay()).toBe(0);
|
|
48
|
+
expect(week.end.getTime() - week.start.getTime()).toBe(7 * 86_400_000);
|
|
49
|
+
|
|
50
|
+
const agenda = calendarVisibleRange("agenda", new Date(2026, 7, 3), 0);
|
|
51
|
+
expect(agenda.end.getTime() - agenda.start.getTime()).toBe(CALENDAR_AGENDA_DAYS * 86_400_000);
|
|
52
|
+
});
|
|
53
|
+
|
|
38
54
|
it("returns Sunday-first weekday labels by default", () => {
|
|
39
55
|
const labels = weekdayLabels(0, "en-US");
|
|
40
56
|
expect(labels[0]).toMatch(/^Sun/);
|
package/src/lib/scheduler.ts
CHANGED
|
@@ -187,6 +187,40 @@ export function getWeekDays(date: Date, weekStartsOn = 0): Date[] {
|
|
|
187
187
|
return Array.from({ length: 7 }, (_, i) => addDays(start, i));
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
/** Inclusive first instant of the agenda window. */
|
|
191
|
+
export const CALENDAR_AGENDA_DAYS = 14;
|
|
192
|
+
|
|
193
|
+
export type CalendarVisibleRange = {
|
|
194
|
+
start: Date;
|
|
195
|
+
/** Exclusive end (start of the day after the last visible day). */
|
|
196
|
+
end: Date;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Days the calendar actually paints for a view.
|
|
201
|
+
* Month includes leading/trailing grid days, not just the named month.
|
|
202
|
+
*/
|
|
203
|
+
export function calendarVisibleRange(
|
|
204
|
+
view: CalendarView,
|
|
205
|
+
date: Date,
|
|
206
|
+
weekStartsOn = 0,
|
|
207
|
+
): CalendarVisibleRange {
|
|
208
|
+
if (view === "month") {
|
|
209
|
+
const grid = getMonthGrid(date, weekStartsOn);
|
|
210
|
+
return { start: grid[0], end: addDays(grid[grid.length - 1], 1) };
|
|
211
|
+
}
|
|
212
|
+
if (view === "week") {
|
|
213
|
+
const days = getWeekDays(date, weekStartsOn);
|
|
214
|
+
return { start: days[0], end: addDays(days[6], 1) };
|
|
215
|
+
}
|
|
216
|
+
if (view === "agenda") {
|
|
217
|
+
const days = agendaDays(date, CALENDAR_AGENDA_DAYS);
|
|
218
|
+
return { start: days[0], end: addDays(days[days.length - 1], 1) };
|
|
219
|
+
}
|
|
220
|
+
const start = startOfDay(date);
|
|
221
|
+
return { start, end: addDays(start, 1) };
|
|
222
|
+
}
|
|
223
|
+
|
|
190
224
|
export function weekdayLabels(weekStartsOn = 0, locale?: string): string[] {
|
|
191
225
|
const sunday = new Date(2026, 7, 2);
|
|
192
226
|
return Array.from({ length: 7 }, (_, i) => {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { NativeSelect } from "./NativeSelect";
|
|
4
|
+
|
|
5
|
+
describe("NativeSelect", () => {
|
|
6
|
+
it("renders a full-width form select by default", () => {
|
|
7
|
+
render(
|
|
8
|
+
<NativeSelect aria-label="Rows">
|
|
9
|
+
<option value="10">10</option>
|
|
10
|
+
</NativeSelect>,
|
|
11
|
+
);
|
|
12
|
+
const select = screen.getByLabelText("Rows");
|
|
13
|
+
expect(select).toHaveAttribute("data-size", "default");
|
|
14
|
+
expect(select).not.toHaveAttribute("size");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("renders a compact toolbar select without the native size attribute", () => {
|
|
18
|
+
render(
|
|
19
|
+
<NativeSelect size="sm" aria-label="Month">
|
|
20
|
+
<option value="7">AUG</option>
|
|
21
|
+
</NativeSelect>,
|
|
22
|
+
);
|
|
23
|
+
const select = screen.getByLabelText("Month");
|
|
24
|
+
expect(select).toHaveAttribute("data-size", "sm");
|
|
25
|
+
expect(select.className).toMatch(/h-8|min-h-8/);
|
|
26
|
+
expect(select).not.toHaveAttribute("size");
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { cn } from "../lib/cn";
|
|
3
|
-
import {
|
|
3
|
+
import { nativeSelectSizeClass, type NativeSelectSize } from "../lib/chips";
|
|
4
|
+
|
|
5
|
+
export type NativeSelectProps = Omit<React.ComponentProps<"select">, "size"> & {
|
|
6
|
+
/**
|
|
7
|
+
* Visual size. `default` stays full-width for forms.
|
|
8
|
+
* `sm` is a compact pill for toolbars. `touch` is a 44px target.
|
|
9
|
+
* Omits the native HTML `size` (visible option rows) to avoid the clash.
|
|
10
|
+
*/
|
|
11
|
+
size?: NativeSelectSize;
|
|
12
|
+
};
|
|
4
13
|
|
|
5
14
|
/**
|
|
6
15
|
* Styled native `<select>` — prefer compound `Select` for custom menus.
|
|
7
16
|
*/
|
|
8
|
-
const NativeSelect = React.forwardRef<HTMLSelectElement,
|
|
9
|
-
({ className, children, ...props }, ref) => (
|
|
17
|
+
const NativeSelect = React.forwardRef<HTMLSelectElement, NativeSelectProps>(
|
|
18
|
+
({ className, size = "default", children, ...props }, ref) => (
|
|
10
19
|
<select
|
|
11
20
|
ref={ref}
|
|
12
21
|
data-slot="native-select"
|
|
13
|
-
|
|
22
|
+
data-size={size}
|
|
23
|
+
className={cn(nativeSelectSizeClass(size), className)}
|
|
14
24
|
{...props}
|
|
15
25
|
>
|
|
16
26
|
{children}
|