@spatika/react 1.3.0 → 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.
Files changed (59) hide show
  1. package/README.md +6 -2
  2. package/dist/composites/EventCalendar.d.ts +13 -2
  3. package/dist/composites/EventCalendar.d.ts.map +1 -1
  4. package/dist/composites/EventCalendar.js +10 -24
  5. package/dist/composites/cartesian-charts.d.ts +12 -2
  6. package/dist/composites/cartesian-charts.d.ts.map +1 -1
  7. package/dist/composites/cartesian-charts.js +27 -13
  8. package/dist/composites/chart-composition.d.ts +19 -1
  9. package/dist/composites/chart-composition.d.ts.map +1 -1
  10. package/dist/composites/chart-composition.js +124 -62
  11. package/dist/composites/chart-interaction.d.ts +81 -0
  12. package/dist/composites/chart-interaction.d.ts.map +1 -0
  13. package/dist/composites/chart-interaction.js +56 -0
  14. package/dist/composites/chart-ui.d.ts +8 -13
  15. package/dist/composites/chart-ui.d.ts.map +1 -1
  16. package/dist/composites/chart-ui.js +9 -6
  17. package/dist/composites/flow-charts.d.ts +6 -1
  18. package/dist/composites/flow-charts.d.ts.map +1 -1
  19. package/dist/composites/flow-charts.js +28 -14
  20. package/dist/composites/radial-charts.d.ts +11 -1
  21. package/dist/composites/radial-charts.d.ts.map +1 -1
  22. package/dist/composites/radial-charts.js +33 -14
  23. package/dist/composites/scheduler-ui.d.ts +14 -1
  24. package/dist/composites/scheduler-ui.d.ts.map +1 -1
  25. package/dist/composites/scheduler-ui.js +23 -2
  26. package/dist/index.d.ts +8 -6
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +4 -4
  29. package/dist/lib/chips.d.ts +3 -0
  30. package/dist/lib/chips.d.ts.map +1 -1
  31. package/dist/lib/chips.js +10 -0
  32. package/dist/lib/scheduler.d.ts +12 -0
  33. package/dist/lib/scheduler.d.ts.map +1 -1
  34. package/dist/lib/scheduler.js +22 -0
  35. package/dist/primitives/NativeSelect.d.ts +10 -1
  36. package/dist/primitives/NativeSelect.d.ts.map +1 -1
  37. package/dist/primitives/NativeSelect.js +2 -2
  38. package/package.json +3 -3
  39. package/skills/spatika-ui/SKILL.md +4 -0
  40. package/src/composites/EventCalendar.tsx +35 -24
  41. package/src/composites/cartesian-charts.test.tsx +86 -2
  42. package/src/composites/cartesian-charts.tsx +84 -16
  43. package/src/composites/chart-composition.test.tsx +15 -0
  44. package/src/composites/chart-composition.tsx +229 -88
  45. package/src/composites/chart-interaction.ts +136 -0
  46. package/src/composites/chart-ui.tsx +35 -27
  47. package/src/composites/flow-charts.test.tsx +21 -2
  48. package/src/composites/flow-charts.tsx +59 -25
  49. package/src/composites/radial-charts.test.tsx +17 -2
  50. package/src/composites/radial-charts.tsx +38 -12
  51. package/src/composites/scheduler-ui.tsx +128 -26
  52. package/src/composites/scheduler.test.tsx +39 -0
  53. package/src/index.test.ts +4 -0
  54. package/src/index.ts +18 -1
  55. package/src/lib/chips.ts +16 -0
  56. package/src/lib/scheduler.test.ts +16 -0
  57. package/src/lib/scheduler.ts +34 -0
  58. package/src/primitives/NativeSelect.test.tsx +28 -0
  59. 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/);
@@ -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 { nativeSelectClass } from "../lib/chips";
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, React.ComponentProps<"select">>(
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
- className={cn(nativeSelectClass, "mt-0", className)}
22
+ data-size={size}
23
+ className={cn(nativeSelectSizeClass(size), className)}
14
24
  {...props}
15
25
  >
16
26
  {children}