@tasknotes/calendar 0.0.0-stage → 0.1.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/LICENSE +21 -0
  3. package/README.md +163 -2
  4. package/dist/calendar.css +1358 -0
  5. package/dist/cjs/core.cjs +716 -0
  6. package/dist/cjs/index.cjs +4240 -0
  7. package/dist/cjs/react.cjs +4068 -0
  8. package/dist/esm/chunk-6RRDNLZM.js +3435 -0
  9. package/dist/esm/chunk-DVMZ5OXN.js +694 -0
  10. package/dist/esm/chunk-L4WKZ6WT.js +0 -0
  11. package/dist/esm/core.js +85 -0
  12. package/dist/esm/index.js +223 -0
  13. package/dist/esm/react.js +46 -0
  14. package/dist/types/core/date.d.cts +30 -0
  15. package/dist/types/core/date.d.ts +30 -0
  16. package/dist/types/core/index.d.cts +7 -0
  17. package/dist/types/core/index.d.ts +7 -0
  18. package/dist/types/core/layout.d.cts +82 -0
  19. package/dist/types/core/layout.d.ts +82 -0
  20. package/dist/types/core/order.d.cts +7 -0
  21. package/dist/types/core/order.d.ts +7 -0
  22. package/dist/types/core/plan.d.cts +42 -0
  23. package/dist/types/core/plan.d.ts +42 -0
  24. package/dist/types/core/store.d.cts +60 -0
  25. package/dist/types/core/store.d.ts +60 -0
  26. package/dist/types/core/types.d.cts +69 -0
  27. package/dist/types/core/types.d.ts +69 -0
  28. package/dist/types/core/zone.d.cts +43 -0
  29. package/dist/types/core/zone.d.ts +43 -0
  30. package/dist/types/dom/calendar.d.cts +215 -0
  31. package/dist/types/dom/calendar.d.ts +215 -0
  32. package/dist/types/dom/context.d.cts +107 -0
  33. package/dist/types/dom/context.d.ts +107 -0
  34. package/dist/types/dom/dom.d.cts +8 -0
  35. package/dist/types/dom/dom.d.ts +8 -0
  36. package/dist/types/dom/format.d.cts +30 -0
  37. package/dist/types/dom/format.d.ts +30 -0
  38. package/dist/types/dom/options.d.cts +401 -0
  39. package/dist/types/dom/options.d.ts +401 -0
  40. package/dist/types/dom/views/daygrid.d.cts +42 -0
  41. package/dist/types/dom/views/daygrid.d.ts +42 -0
  42. package/dist/types/dom/views/list.d.cts +27 -0
  43. package/dist/types/dom/views/list.d.ts +27 -0
  44. package/dist/types/dom/views/timegrid.d.cts +54 -0
  45. package/dist/types/dom/views/timegrid.d.ts +54 -0
  46. package/dist/types/dom/views/timeline.d.cts +83 -0
  47. package/dist/types/dom/views/timeline.d.ts +83 -0
  48. package/dist/types/dom/views/year.d.cts +26 -0
  49. package/dist/types/dom/views/year.d.ts +26 -0
  50. package/dist/types/index.d.cts +6 -0
  51. package/dist/types/index.d.ts +6 -0
  52. package/dist/types/react/index.d.cts +20 -0
  53. package/dist/types/react/index.d.ts +20 -0
  54. package/dist/types/tasknotes/bases.d.cts +50 -0
  55. package/dist/types/tasknotes/bases.d.ts +50 -0
  56. package/package.json +108 -5
@@ -0,0 +1,83 @@
1
+ import { type Day } from "../../core/date.cjs";
2
+ import type { StoreChange } from "../../core/store.cjs";
3
+ import { type Selection, type View, type ViewContext } from "../context.cjs";
4
+ import { type Hit } from "../options.cjs";
5
+ /**
6
+ * Gantt-style timeline: one row per `TimelineRow`, bars positioned on civil
7
+ * days so DST never stretches a day.
8
+ */
9
+ export declare class TimelineView<D> implements View {
10
+ private readonly ctx;
11
+ readonly el: HTMLElement;
12
+ private readonly scroller;
13
+ private readonly canvas;
14
+ private readonly head;
15
+ private readonly ticks;
16
+ private readonly rowsEl;
17
+ private readonly svg;
18
+ private readonly todayLine;
19
+ private readonly todayTag;
20
+ private readonly selLayer;
21
+ private rows;
22
+ private readonly scale;
23
+ private readonly dayWidth;
24
+ private readonly startDay;
25
+ private readonly endDay;
26
+ private readonly labelWidth;
27
+ private readonly rowHeight;
28
+ private link;
29
+ private get tl();
30
+ constructor(ctx: ViewContext<D>);
31
+ private trackWidth;
32
+ /** X offset (within the track) of an instant. */
33
+ private x;
34
+ private xDay;
35
+ /** Instant at a track x offset. */
36
+ private msAt;
37
+ /** Viewport x (from the scroller's left edge) where the track starts showing, and its visible width. */
38
+ private trackViewport;
39
+ /** Instant under a viewport x, measured from the scroller's left edge. */
40
+ instantAt(viewportX: number): number;
41
+ /** Viewport x of an instant at the current scroll. */
42
+ viewportXOf(ms: number): number;
43
+ /** Scrolls so `ms` sits at `viewportX`. */
44
+ placeInstant(ms: number, viewportX: number, smooth?: boolean): void;
45
+ scrollToInstant(ms: number, align: "start" | "center" | "end", smooth: boolean): void;
46
+ /** Viewport x of the middle of the visible track. */
47
+ viewportCentre(): number;
48
+ /** The scroller's left edge in client coordinates. */
49
+ viewportLeft(): number;
50
+ private scrollLeftTo;
51
+ private buildHead;
52
+ private mountRow;
53
+ private unmountRow;
54
+ render(_change: StoreChange | null): void;
55
+ private placeBar;
56
+ private rowOfItem;
57
+ /** Track x of a bar's start or finish edge. */
58
+ private edgeX;
59
+ private drawDependencies;
60
+ private linkTargetAt;
61
+ /** Centre of a target edge's port, in track coordinates. */
62
+ private targetPoint;
63
+ private linkArg;
64
+ private linkState;
65
+ private markTarget;
66
+ private readonly onLinkDown;
67
+ private endLink;
68
+ showSelection(sel: Selection | null): void;
69
+ hit(x: number, y: number): Hit | null;
70
+ tick(): void;
71
+ /** Scrolls so `day` sits a little in from the left edge. */
72
+ scrollToDay(day: Day): void;
73
+ getScroll(): {
74
+ top: number;
75
+ left: number;
76
+ };
77
+ setScroll(s: {
78
+ top: number;
79
+ left: number;
80
+ }): void;
81
+ elementsFor(id: string): HTMLElement[];
82
+ destroy(): void;
83
+ }
@@ -0,0 +1,83 @@
1
+ import { type Day } from "../../core/date.js";
2
+ import type { StoreChange } from "../../core/store.js";
3
+ import { type Selection, type View, type ViewContext } from "../context.js";
4
+ import { type Hit } from "../options.js";
5
+ /**
6
+ * Gantt-style timeline: one row per `TimelineRow`, bars positioned on civil
7
+ * days so DST never stretches a day.
8
+ */
9
+ export declare class TimelineView<D> implements View {
10
+ private readonly ctx;
11
+ readonly el: HTMLElement;
12
+ private readonly scroller;
13
+ private readonly canvas;
14
+ private readonly head;
15
+ private readonly ticks;
16
+ private readonly rowsEl;
17
+ private readonly svg;
18
+ private readonly todayLine;
19
+ private readonly todayTag;
20
+ private readonly selLayer;
21
+ private rows;
22
+ private readonly scale;
23
+ private readonly dayWidth;
24
+ private readonly startDay;
25
+ private readonly endDay;
26
+ private readonly labelWidth;
27
+ private readonly rowHeight;
28
+ private link;
29
+ private get tl();
30
+ constructor(ctx: ViewContext<D>);
31
+ private trackWidth;
32
+ /** X offset (within the track) of an instant. */
33
+ private x;
34
+ private xDay;
35
+ /** Instant at a track x offset. */
36
+ private msAt;
37
+ /** Viewport x (from the scroller's left edge) where the track starts showing, and its visible width. */
38
+ private trackViewport;
39
+ /** Instant under a viewport x, measured from the scroller's left edge. */
40
+ instantAt(viewportX: number): number;
41
+ /** Viewport x of an instant at the current scroll. */
42
+ viewportXOf(ms: number): number;
43
+ /** Scrolls so `ms` sits at `viewportX`. */
44
+ placeInstant(ms: number, viewportX: number, smooth?: boolean): void;
45
+ scrollToInstant(ms: number, align: "start" | "center" | "end", smooth: boolean): void;
46
+ /** Viewport x of the middle of the visible track. */
47
+ viewportCentre(): number;
48
+ /** The scroller's left edge in client coordinates. */
49
+ viewportLeft(): number;
50
+ private scrollLeftTo;
51
+ private buildHead;
52
+ private mountRow;
53
+ private unmountRow;
54
+ render(_change: StoreChange | null): void;
55
+ private placeBar;
56
+ private rowOfItem;
57
+ /** Track x of a bar's start or finish edge. */
58
+ private edgeX;
59
+ private drawDependencies;
60
+ private linkTargetAt;
61
+ /** Centre of a target edge's port, in track coordinates. */
62
+ private targetPoint;
63
+ private linkArg;
64
+ private linkState;
65
+ private markTarget;
66
+ private readonly onLinkDown;
67
+ private endLink;
68
+ showSelection(sel: Selection | null): void;
69
+ hit(x: number, y: number): Hit | null;
70
+ tick(): void;
71
+ /** Scrolls so `day` sits a little in from the left edge. */
72
+ scrollToDay(day: Day): void;
73
+ getScroll(): {
74
+ top: number;
75
+ left: number;
76
+ };
77
+ setScroll(s: {
78
+ top: number;
79
+ left: number;
80
+ }): void;
81
+ elementsFor(id: string): HTMLElement[];
82
+ destroy(): void;
83
+ }
@@ -0,0 +1,26 @@
1
+ import { type Day } from "../../core/date.cjs";
2
+ import type { StoreChange } from "../../core/store.cjs";
3
+ import type { Selection, View, ViewContext } from "../context.cjs";
4
+ import type { Hit } from "../options.cjs";
5
+ /** Twelve compact months. Each day shows how busy it is; clicking opens it. */
6
+ export declare class YearView<D> implements View {
7
+ private readonly ctx;
8
+ readonly el: HTMLElement;
9
+ private readonly scroller;
10
+ private cells;
11
+ constructor(ctx: ViewContext<D>);
12
+ render(_change: StoreChange | null): void;
13
+ showSelection(_sel: Selection | null): void;
14
+ hit(x: number, y: number): Hit | null;
15
+ dayAt(el: Element): Day | null;
16
+ getScroll(): {
17
+ top: number;
18
+ left: number;
19
+ };
20
+ setScroll(s: {
21
+ top: number;
22
+ left: number;
23
+ }): void;
24
+ elementsFor(_id: string): HTMLElement[];
25
+ destroy(): void;
26
+ }
@@ -0,0 +1,26 @@
1
+ import { type Day } from "../../core/date.js";
2
+ import type { StoreChange } from "../../core/store.js";
3
+ import type { Selection, View, ViewContext } from "../context.js";
4
+ import type { Hit } from "../options.js";
5
+ /** Twelve compact months. Each day shows how busy it is; clicking opens it. */
6
+ export declare class YearView<D> implements View {
7
+ private readonly ctx;
8
+ readonly el: HTMLElement;
9
+ private readonly scroller;
10
+ private cells;
11
+ constructor(ctx: ViewContext<D>);
12
+ render(_change: StoreChange | null): void;
13
+ showSelection(_sel: Selection | null): void;
14
+ hit(x: number, y: number): Hit | null;
15
+ dayAt(el: Element): Day | null;
16
+ getScroll(): {
17
+ top: number;
18
+ left: number;
19
+ };
20
+ setScroll(s: {
21
+ top: number;
22
+ left: number;
23
+ }): void;
24
+ elementsFor(_id: string): HTMLElement[];
25
+ destroy(): void;
26
+ }
@@ -0,0 +1,6 @@
1
+ export * from "./core/index.cjs";
2
+ export { Calendar } from "./dom/calendar.cjs";
3
+ export type { ElMeta, Selection, Variant } from "./dom/context.cjs";
4
+ export { Formatter, localeFirstDay } from "./dom/format.cjs";
5
+ export * from "./dom/options.cjs";
6
+ export * from "./tasknotes/bases.cjs";
@@ -0,0 +1,6 @@
1
+ export * from "./core/index.js";
2
+ export { Calendar } from "./dom/calendar.js";
3
+ export type { ElMeta, Selection, Variant } from "./dom/context.js";
4
+ export { Formatter, localeFirstDay } from "./dom/format.js";
5
+ export * from "./dom/options.js";
6
+ export * from "./tasknotes/bases.js";
@@ -0,0 +1,20 @@
1
+ import { type CSSProperties } from "react";
2
+ import type { CalendarItem } from "../core/types.cjs";
3
+ import { Calendar } from "../dom/calendar.cjs";
4
+ import type { CalendarOptions } from "../dom/options.cjs";
5
+ export interface TaskCalendarProps<D> extends Partial<CalendarOptions<D>> {
6
+ items: readonly CalendarItem<D>[];
7
+ className?: string;
8
+ style?: CSSProperties;
9
+ /** Receives the Calendar instance (null on unmount). */
10
+ calendarRef?: (calendar: Calendar<D> | null) => void;
11
+ /** Change to force a full re-render, e.g. when render hooks read new state. */
12
+ renderKey?: unknown;
13
+ }
14
+ /**
15
+ * React binding. Options are diffed by value, so inline callbacks and object
16
+ * literals do not cause rebuilds; callbacks always see the latest props.
17
+ */
18
+ export declare function TaskCalendar<D = unknown>(props: TaskCalendarProps<D>): import("react").JSX.Element;
19
+ export { Calendar };
20
+ export type { CalendarItem, CalendarOptions };
@@ -0,0 +1,20 @@
1
+ import { type CSSProperties } from "react";
2
+ import type { CalendarItem } from "../core/types.js";
3
+ import { Calendar } from "../dom/calendar.js";
4
+ import type { CalendarOptions } from "../dom/options.js";
5
+ export interface TaskCalendarProps<D> extends Partial<CalendarOptions<D>> {
6
+ items: readonly CalendarItem<D>[];
7
+ className?: string;
8
+ style?: CSSProperties;
9
+ /** Receives the Calendar instance (null on unmount). */
10
+ calendarRef?: (calendar: Calendar<D> | null) => void;
11
+ /** Change to force a full re-render, e.g. when render hooks read new state. */
12
+ renderKey?: unknown;
13
+ }
14
+ /**
15
+ * React binding. Options are diffed by value, so inline callbacks and object
16
+ * literals do not cause rebuilds; callbacks always see the latest props.
17
+ */
18
+ export declare function TaskCalendar<D = unknown>(props: TaskCalendarProps<D>): import("react").JSX.Element;
19
+ export { Calendar };
20
+ export type { CalendarItem, CalendarOptions };
@@ -0,0 +1,50 @@
1
+ import type { CalendarOptions, ViewType } from "../dom/options.cjs";
2
+ /** View names stored in `.base` files (FullCalendar's names, kept for compatibility). */
3
+ export type BasesCalendarViewName = "dayGridMonth" | "timeGridWeek" | "timeGridCustom" | "timeGridDay" | "listWeek" | "multiMonthYear";
4
+ export declare function viewFromBases(name: string | null | undefined, fallback?: ViewType): ViewType;
5
+ export declare function viewToBases(view: ViewType): BasesCalendarViewName | null;
6
+ /**
7
+ * Layout settings of the TaskNotes calendar Bases view, as stored in `.base`
8
+ * files (event toggles and data settings are not layout and are not here).
9
+ */
10
+ export interface BasesCalendarLayout {
11
+ calendarView?: string | null;
12
+ customDayCount?: number | null;
13
+ listDayCount?: number | null;
14
+ heightMode?: string | null;
15
+ firstDay?: string | number | null;
16
+ timeFormat?: string | null;
17
+ weekNumbers?: boolean | null;
18
+ showWeekends?: boolean | null;
19
+ showAllDaySlot?: boolean | null;
20
+ showTodayHighlight?: boolean | null;
21
+ todayColumnWidthMultiplier?: number | null;
22
+ slotMinTime?: string | null;
23
+ slotMaxTime?: string | null;
24
+ slotDuration?: string | null;
25
+ snapDuration?: string | null;
26
+ scrollTime?: string | null;
27
+ nowIndicator?: boolean | null;
28
+ showTimeGrid?: boolean | null;
29
+ selectMirror?: boolean | null;
30
+ slotEventOverlap?: boolean | null;
31
+ eventMinHeight?: number | null;
32
+ eventMaxStack?: number | null;
33
+ dayMaxEvents?: number | boolean | null;
34
+ dayMaxEventRows?: number | boolean | null;
35
+ locale?: string | null;
36
+ }
37
+ /** Defaults used by TaskNotes when a key is absent. */
38
+ export declare const BASES_CALENDAR_DEFAULTS: Required<{
39
+ [K in keyof BasesCalendarLayout]: NonNullable<BasesCalendarLayout[K]>;
40
+ }>;
41
+ /** "HH:MM[:SS]" check with the same limits TaskNotes enforces. */
42
+ export declare function isValidSlotTime(value: string, maxHours?: number): boolean;
43
+ /**
44
+ * Converts Bases calendar settings to calendar options, applying the same
45
+ * normalisation the FullCalendar-based view did, so existing `.base` files
46
+ * keep their behaviour.
47
+ */
48
+ export declare function basesLayoutOptions<D>(s: BasesCalendarLayout, context?: {
49
+ embedded?: boolean;
50
+ }): Partial<CalendarOptions<D>>;
@@ -0,0 +1,50 @@
1
+ import type { CalendarOptions, ViewType } from "../dom/options.js";
2
+ /** View names stored in `.base` files (FullCalendar's names, kept for compatibility). */
3
+ export type BasesCalendarViewName = "dayGridMonth" | "timeGridWeek" | "timeGridCustom" | "timeGridDay" | "listWeek" | "multiMonthYear";
4
+ export declare function viewFromBases(name: string | null | undefined, fallback?: ViewType): ViewType;
5
+ export declare function viewToBases(view: ViewType): BasesCalendarViewName | null;
6
+ /**
7
+ * Layout settings of the TaskNotes calendar Bases view, as stored in `.base`
8
+ * files (event toggles and data settings are not layout and are not here).
9
+ */
10
+ export interface BasesCalendarLayout {
11
+ calendarView?: string | null;
12
+ customDayCount?: number | null;
13
+ listDayCount?: number | null;
14
+ heightMode?: string | null;
15
+ firstDay?: string | number | null;
16
+ timeFormat?: string | null;
17
+ weekNumbers?: boolean | null;
18
+ showWeekends?: boolean | null;
19
+ showAllDaySlot?: boolean | null;
20
+ showTodayHighlight?: boolean | null;
21
+ todayColumnWidthMultiplier?: number | null;
22
+ slotMinTime?: string | null;
23
+ slotMaxTime?: string | null;
24
+ slotDuration?: string | null;
25
+ snapDuration?: string | null;
26
+ scrollTime?: string | null;
27
+ nowIndicator?: boolean | null;
28
+ showTimeGrid?: boolean | null;
29
+ selectMirror?: boolean | null;
30
+ slotEventOverlap?: boolean | null;
31
+ eventMinHeight?: number | null;
32
+ eventMaxStack?: number | null;
33
+ dayMaxEvents?: number | boolean | null;
34
+ dayMaxEventRows?: number | boolean | null;
35
+ locale?: string | null;
36
+ }
37
+ /** Defaults used by TaskNotes when a key is absent. */
38
+ export declare const BASES_CALENDAR_DEFAULTS: Required<{
39
+ [K in keyof BasesCalendarLayout]: NonNullable<BasesCalendarLayout[K]>;
40
+ }>;
41
+ /** "HH:MM[:SS]" check with the same limits TaskNotes enforces. */
42
+ export declare function isValidSlotTime(value: string, maxHours?: number): boolean;
43
+ /**
44
+ * Converts Bases calendar settings to calendar options, applying the same
45
+ * normalisation the FullCalendar-based view did, so existing `.base` files
46
+ * keep their behaviour.
47
+ */
48
+ export declare function basesLayoutOptions<D>(s: BasesCalendarLayout, context?: {
49
+ embedded?: boolean;
50
+ }): Partial<CalendarOptions<D>>;
package/package.json CHANGED
@@ -1,6 +1,109 @@
1
1
  {
2
- "name": "@tasknotes/calendar",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@tasknotes/calendar",
3
+ "version": "0.1.1",
4
+ "description": "Task-native calendar engine for TaskNotes: incremental layout, time grid, month, list, year and timeline views.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/callumalpass/tasknotes-calendar.git"
10
+ },
11
+ "keywords": [
12
+ "calendar",
13
+ "tasknotes",
14
+ "timeline",
15
+ "scheduling",
16
+ "typescript",
17
+ "obsidian"
18
+ ],
19
+ "bugs": {
20
+ "url": "https://github.com/callumalpass/tasknotes-calendar/issues"
21
+ },
22
+ "homepage": "https://github.com/callumalpass/tasknotes-calendar#readme",
23
+ "engines": {
24
+ "node": ">=22"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "main": "./dist/cjs/index.cjs",
30
+ "module": "./dist/esm/index.js",
31
+ "types": "./dist/types/index.d.ts",
32
+ "exports": {
33
+ ".": {
34
+ "import": {
35
+ "types": "./dist/types/index.d.ts",
36
+ "default": "./dist/esm/index.js"
37
+ },
38
+ "require": {
39
+ "types": "./dist/types/index.d.cts",
40
+ "default": "./dist/cjs/index.cjs"
41
+ }
42
+ },
43
+ "./core": {
44
+ "import": {
45
+ "types": "./dist/types/core/index.d.ts",
46
+ "default": "./dist/esm/core.js"
47
+ },
48
+ "require": {
49
+ "types": "./dist/types/core/index.d.cts",
50
+ "default": "./dist/cjs/core.cjs"
51
+ }
52
+ },
53
+ "./react": {
54
+ "import": {
55
+ "types": "./dist/types/react/index.d.ts",
56
+ "default": "./dist/esm/react.js"
57
+ },
58
+ "require": {
59
+ "types": "./dist/types/react/index.d.cts",
60
+ "default": "./dist/cjs/react.cjs"
61
+ }
62
+ },
63
+ "./calendar.css": "./dist/calendar.css"
64
+ },
65
+ "files": [
66
+ "dist",
67
+ "README.md",
68
+ "CHANGELOG.md",
69
+ "LICENSE"
70
+ ],
71
+ "sideEffects": [
72
+ "*.css"
73
+ ],
74
+ "peerDependencies": {
75
+ "react": ">=18"
76
+ },
77
+ "peerDependenciesMeta": {
78
+ "react": {
79
+ "optional": true
80
+ }
81
+ },
82
+ "scripts": {
83
+ "clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"",
84
+ "build": "npm run clean && node scripts/build.mjs && tsc -p tsconfig.types.json && node scripts/declarations.mjs",
85
+ "typecheck": "tsc -p tsconfig.json --noEmit",
86
+ "lint": "eslint src test",
87
+ "test": "vitest run",
88
+ "test:watch": "vitest",
89
+ "test:browser": "playwright test",
90
+ "test:package": "node scripts/smoke-package.mjs",
91
+ "playground": "node scripts/playground.mjs",
92
+ "prepack": "npm run build"
93
+ },
94
+ "devDependencies": {
95
+ "@axe-core/playwright": "4.14.0",
96
+ "@playwright/test": "1.64.1",
97
+ "@types/react": "^19.3.0",
98
+ "@types/react-dom": "^19.3.0",
99
+ "esbuild": "^0.28.2",
100
+ "eslint": "^9.39.5",
101
+ "happy-dom": "^21.0.4",
102
+ "react": "^19.3.1",
103
+ "react-dom": "^19.3.1",
104
+ "typescript": "^5.9.3",
105
+ "typescript-eslint": "^8.72.0",
106
+ "vite": "^8.3.5",
107
+ "vitest": "^5.0.5"
108
+ }
109
+ }