cleanplate 0.2.7 → 0.2.8

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 (34) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/components/form-controls/Date.d.ts +27 -7
  3. package/dist/components/form-controls/Date.d.ts.map +1 -1
  4. package/dist/components/form-controls/date/DatePickerFooter.d.ts +8 -0
  5. package/dist/components/form-controls/date/DatePickerFooter.d.ts.map +1 -0
  6. package/dist/components/form-controls/date/DatePickerGrid.d.ts +18 -0
  7. package/dist/components/form-controls/date/DatePickerGrid.d.ts.map +1 -0
  8. package/dist/components/form-controls/date/DatePickerHeader.d.ts +21 -0
  9. package/dist/components/form-controls/date/DatePickerHeader.d.ts.map +1 -0
  10. package/dist/components/form-controls/date/DatePickerPanel.d.ts +15 -0
  11. package/dist/components/form-controls/date/DatePickerPanel.d.ts.map +1 -0
  12. package/dist/components/form-controls/date/ScrollPicker.d.ts +16 -0
  13. package/dist/components/form-controls/date/ScrollPicker.d.ts.map +1 -0
  14. package/dist/components/form-controls/date/calendar-matrix.d.ts +6 -0
  15. package/dist/components/form-controls/date/calendar-matrix.d.ts.map +1 -0
  16. package/dist/components/form-controls/date/date-constraints.d.ts +7 -0
  17. package/dist/components/form-controls/date/date-constraints.d.ts.map +1 -0
  18. package/dist/components/form-controls/date/date-types.d.ts +8 -0
  19. package/dist/components/form-controls/date/date-types.d.ts.map +1 -0
  20. package/dist/components/form-controls/date/normalize-date.d.ts +13 -0
  21. package/dist/components/form-controls/date/normalize-date.d.ts.map +1 -0
  22. package/dist/components/form-controls/date/use-date-picker-state.d.ts +27 -0
  23. package/dist/components/form-controls/date/use-date-picker-state.d.ts.map +1 -0
  24. package/dist/components/form-controls/date/use-media-query.d.ts +2 -0
  25. package/dist/components/form-controls/date/use-media-query.d.ts.map +1 -0
  26. package/dist/index.css +1 -1
  27. package/dist/index.es.css +1 -1
  28. package/dist/index.es.js +4 -4
  29. package/dist/index.js +4 -4
  30. package/docs/FormControls.md +19 -4
  31. package/docs/superpowers/plans/2026-05-10-date-picker.md +955 -0
  32. package/docs/superpowers/specs/2026-05-10-date-picker-design.md +196 -0
  33. package/llms.txt +2 -2
  34. package/package.json +21 -8
@@ -0,0 +1,196 @@
1
+ # Date picker (`Date` form control) — design spec
2
+
3
+ **Status:** Approved (chat sign-off 2026-05-10)
4
+ **Scope:** Replace existing three-`Select` `Date` field with calendar date picker per product requirements.
5
+ **Stack:** React 18+, `date-fns` (granular imports), `@floating-ui/react` (already in package).
6
+
7
+ ---
8
+
9
+ ## 1. Summary
10
+
11
+ The public **`Date`** export from form controls becomes a **calendar-based date picker**: read-only trigger field, floating **popover** on desktop and **bottom sheet** on mobile (same breakpoint and shell pattern as `Select.tsx`), **Cancel / OK** staged commit, full constraint props, and accessibility per the requirements document. This is a **breaking API** change from the previous day/month/year string model.
12
+
13
+ ---
14
+
15
+ ## 2. Goals and non-goals
16
+
17
+ **In scope** (aligned with `datepicker-requirements.md` and wireframe):
18
+
19
+ - Single date selection; **staging** in the panel; **OK** commits (fires `onChange`, updates display); **Cancel** / Escape / outside dismiss / overlay tap **revert** to last committed value only.
20
+ - Month grid (7 columns, configurable `weekStartsOn`); **today** distinct from **selected**; **outside-month** cells visible, dimmed; click outside-month **navigates** to that month and **stages** that date.
21
+ - Month and year **chevrons** plus **dropdown** subviews; navigation **clamped** by `minDate` / `maxDate`.
22
+ - Constraints: `minDate`, `maxDate`, `disabledDates`, `disabledDaysOfWeek`.
23
+ - Locale via `date-fns` `Locale` and `weekStartsOn`.
24
+ - Keyboard and ARIA (`grid` / `gridcell`, `aria-selected`, `aria-disabled`, trigger `aria-expanded` / `aria-controls`, focus restoration on close).
25
+ - Responsive: desktop popover (**280px** width, flip/shift, 8px viewport padding); mobile sheet (rounded top corners, dim overlay, no swipe-dismiss), body scroll lock while open.
26
+
27
+ **Explicitly out of scope** for this component (unchanged from requirements):
28
+
29
+ - Range / dual calendar, time picker, typed free-form parsing, timezone UI, gestures, inline-only calendar embedding.
30
+
31
+ ---
32
+
33
+ ## 3. Breaking changes
34
+
35
+ Previous behaviour:
36
+
37
+ - Three `Select` fields; `onChange` emitted **`dd-mm-yyyy`** string; `defaultValue` used `"--"` split pattern.
38
+
39
+ New behaviour:
40
+
41
+ - `value` / `defaultValue`: **`Date | null`** (calendar date in **local** timezone; comparisons use **local calendar midnight** consistently — document in implementation and JSDoc).
42
+ - `onChange`: **`(date: Date | null) => void`**.
43
+ - Clearing via trigger **commits `null` immediately** (closes panel if open).
44
+
45
+ **Migration:** Consumers must replace string state with `Date` (or derive strings at form submit). Optionally use hidden `name` field (see below) for native forms.
46
+
47
+ ---
48
+
49
+ ## 4. Architecture (Approach 2)
50
+
51
+ **Facade + module folder** — keeps a single public **`Date`** / **`DateProps`** while splitting implementation for testability and maintainability.
52
+
53
+ | Area | Responsibility |
54
+ |------|----------------|
55
+ | `form-controls/Date.tsx` | Public API, field chrome (label, error, `isFluid`, `dataTestId`, ids), wires shell + panel. |
56
+ | `form-controls/date/calendar-matrix.ts` | Builds visible calendar cells / weeks using `date-fns` granular imports only. |
57
+ | `form-controls/date/date-constraints.ts` | `isDisabled`, nav bounds, weekday / blackout rules vs `min`/`max`. |
58
+ | `form-controls/date/use-date-picker-state.ts` | `open`, committed vs staged value, view mode (`calendar` \| `month` \| `year`), actions. |
59
+ | `form-controls/date/DatePickerPanel.tsx` | Header, grid, footer **Cancel** / **OK**. |
60
+ | `form-controls/date/MonthDropdownView.tsx` | Scrollable month list; clamp to allowed months. |
61
+ | `form-controls/date/YearDropdownView.tsx` | Scrollable year list; clamp to allowed years. |
62
+
63
+ Optional later extractions if files grow: shared **`ScrollPickerList`**; shared **responsive shell** hook extracted from duplication with `Select` (only if duplication hurts — not required in first PR).
64
+
65
+ ---
66
+
67
+ ## 5. Tree-shaking notes
68
+
69
+ - **Runtime:** Always import **`date-fns`** as **named submodule imports** (e.g. `import { format } from 'date-fns/format'` or equivalent tree-shake-friendly entry — follow project ESLint / bundler conventions).
70
+ - **Package layout:** The published library currently uses a **single Rollup entry** (`src/index.js`) that imports `FormControls`; consumers importing the main entry may still include form controls as a group. **True** “only pay for Date” at app level may require a **future** `package.json` **`exports`** subpath (out of scope for this design unless explicitly added in the same effort). This spec still requires **no unnecessary eager imports** inside the date module.
71
+
72
+ ---
73
+
74
+ ## 6. Responsive shell (mirror `Select`)
75
+
76
+ - **Breakpoint:** `(max-width: 768px)` matches `Select.tsx` (`SELECT_MOBILE_SHEET_MEDIA`).
77
+ - **Desktop:** `FloatingPortal` + `useFloating` with `offset`, `flip`, `shift`; popover **width 280px** (not input width); `placement` overridable via prop (default `bottom-start`); `autoUpdate` while open.
78
+ - **Mobile:** Fixed bottom sheet, dim backdrop, `translateY` enter/exit, `transitionend` + timeout fallback, **`document.body.style.overflow = 'hidden'`** while open (same rationale as Select).
79
+ - **Dismiss:** Outside press / overlay tap behave as **Cancel** (discard staged).
80
+
81
+ SCSS timings and z-index should **reuse or align with** `--cp-select-*` tokens / class patterns in `FormControls.module.scss` to avoid visual regressions and drift.
82
+
83
+ ---
84
+
85
+ ## 7. Behaviour details
86
+
87
+ - **Opening:** Copies **committed → staged**. If no committed value, stage **today** clamped into allowed range, or first allowed day of **`displayedMonth`** if today invalid (implementation picks one deterministic rule — prefer **clamp today**, else **first enabled day of month** visible).
88
+ - **OK:** Applies staged → committed; `onChange(committed)`; close; restore focus per a11y section.
89
+ - **Cancel / Escape / outside dismiss:** Discard staged; close; no `onChange` unless clearing was instantaneous (clear is separate).
90
+ - **Clear:** **Instant** commit `null`, `onChange(null)`, close if open.
91
+ - **Disabled:** No open when `isDisabled`; nav controls and dropdown options respect disabled state for out-of-range or invalid targets.
92
+ - **Hidden input:** If `name` is provided, render `<input type="hidden" name={name}>` with value **`YYYY-MM-DD`** when committed value exists, otherwise empty string.
93
+
94
+ ---
95
+
96
+ ## 8. Accessibility
97
+
98
+ - Trigger: **`aria-expanded`**, **`aria-controls`** referencing panel id; labelled via `label` + `id` pattern consistent with form controls.
99
+ - Mobile sheet container: **`role="dialog"`**, **`aria-modal="true"`**; desktop popover remains focusable-managed surface (exact `role` may be `dialog` or documented pattern consistent with axe rules — implementation verifies with axe in Storybook or CI when available).
100
+ - Grid: **`role="grid"`**, cells **`role="gridcell"`**; **`aria-selected`** on selection; **`tabIndex={-1}`** vs roving tabindex strategy as implemented; **disabled** cells **`aria-disabled="true"`** and not in tab order.
101
+ - **Today** vs **selected**: not color-only (e.g. subtle ring or textual “today” available to SR via `aria-label` on cell).
102
+ - **Focus:** On open, move focus into panel; on close return focus to trigger. **Tab** cycles within the picker while open (**lightweight in-house Tab loop** first; introduce `focus-trap-react` only if manual handling fails review or tests).
103
+
104
+ Keyboard behaviour matches requirements doc:
105
+
106
+ | Key | Behaviour |
107
+ |-----|-----------|
108
+ | Tab / Shift+Tab | Cycle within open picker (within surface only while open). |
109
+ | Enter / Space on trigger | Open picker. |
110
+ | Arrows | Move between enabled days / within grid semantics. |
111
+ | Enter / Space on day | Stage date. |
112
+ | Page Up / Down | Previous / next month. |
113
+ | Home / End | First / last day of **currently displayed** month (enabled handling if some days disabled). |
114
+ | Escape | Cancel and close |
115
+
116
+ ---
117
+
118
+ ## 9. Props (public API)
119
+
120
+ Compatible with refined requirements (`datepicker-requirements.md`) with naming aligned to existing form controls where useful:
121
+
122
+ | Prop | Type | Notes |
123
+ |------|------|--------|
124
+ | `value` | `Date \| null` | Controlled. |
125
+ | `defaultValue` | `Date \| null` | Uncontrolled initial. |
126
+ | `onChange` | `(date: Date \| null) => void` | Fires on **OK** or **instant clear**. |
127
+ | `placeholder` | `string` | Default `Select date`. |
128
+ | `dateFormat` | `string` | Default `MMM dd, yyyy`; use `date-fns` `format`. |
129
+ | `id`, `name` | `string` | `name` enables hidden ISO field. |
130
+ | `minDate`, `maxDate` | `Date` | Inclusive bounds on calendar dates. |
131
+ | `disabledDates` | `Date[]` | Normalized to date-only compare. |
132
+ | `disabledDaysOfWeek` | `number[]` | `0` Sun … `6` Sat. |
133
+ | `locale` | `Locale` | `date-fns` locale. |
134
+ | `weekStartsOn` | `0 \| … \| 6` | Default `0`. |
135
+ | `clearable` | `boolean` | Default `true`. |
136
+ | `disabled` | `boolean` | Align prop name with other controls (`isDisabled` deprecated alias optional — **YAGNI**: use `disabled` only if we standardize; else keep `isDisabled` for consistency with `Select` — **decision: keep `isDisabled`** to match existing `Date.tsx` and `Select.tsx` until a global rename). |
137
+ | `readOnly` | `boolean` | Per requirements. |
138
+ | `label`, `error` | `string` | Match existing field patterns. |
139
+ | `isFluid`, `dataTestId`, `isRequired` | | Preserve from current `Date`. |
140
+ | `popoverPlacement` | `Placement` | `@floating-ui/react`. |
141
+ | `onOpen`, `onClose` | `() => void` | |
142
+
143
+ **Note:** Requirements used `disabled`; existing components use **`isDisabled`**. This spec **standardizes on `isDisabled`** for continuity with `Select` / prior `Date` until a library-wide rename.
144
+
145
+ ---
146
+
147
+ ## 10. Testing (TDD)
148
+
149
+ **Tooling:** Add **Vitest**, **@testing-library/react**, **jsdom** (+ any minimal config for TSX path aliases).
150
+
151
+ **Order:**
152
+
153
+ 1. **Unit:** `calendar-matrix.ts`, `date-constraints.ts` — edge cases (leap years, DST boundaries treated as local date-only, boundary min/max months, weekdays).
154
+ 2. **Hook / state:** `use-date-picker-state` — open/close, commit/cancel, month/year navigation clamps, staged vs committed.
155
+ 3. **RTL:** OK vs Cancel vs outside-click vs Escape; disabled day interaction; clear button commits `null`; optional snapshot of header rendering.
156
+
157
+ Stories (Storybook): desktop vs mobile layouts, constrained DOB scenario, weekday blackout — scheduled after core tests pass.
158
+
159
+ ---
160
+
161
+ ## 11. Dependencies
162
+
163
+ | Package | Role |
164
+ |---------|------|
165
+ | `date-fns` | **New** dependency — formatting, arithmetic, locale. |
166
+ | `@floating-ui/react` | Existing — positioning. |
167
+
168
+ No headless UI library.
169
+
170
+ ---
171
+
172
+ ## 12. Files to touch (implementation preview)
173
+
174
+ - Replace `src/components/form-controls/Date.tsx`.
175
+ - Add `src/components/form-controls/date/*` as above.
176
+ - Extend `FormControls.module.scss` for date picker (tokens aligned with select sheet/dropdown).
177
+ - `package.json` — add `date-fns`, test deps, `test` script.
178
+ - Storybook stories under existing form-controls stories pattern.
179
+ - **Changelog / migration note** for breaking `Date` API (where the project publishes changes).
180
+
181
+ ---
182
+
183
+ ## 13. Self-review checklist (pre-implementation)
184
+
185
+ - [x] No unresolved “TBD” in behaviour: focus strategy starts in-house Tab loop; clamp rule for empty-open documented in §7.
186
+ - [x] `isDisabled` vs `disabled` contradiction resolved (**use `isDisabled`**).
187
+ - [x] Timezone stance: **local calendar date only** for v1.
188
+ - [x] Scope fits one implementation plan with optional follow-up for `package.json` exports.
189
+
190
+ ---
191
+
192
+ ## 14. References
193
+
194
+ - Product requirements (authoritative checklist): companion doc `datepicker-requirements.md` (user-provided).
195
+ - Visual: wireframe `assets/Screenshot_2026-05-10_at_3.54.33_PM-29e15a23-18c8-40cb-a7e3-2941980c2d4a.png`.
196
+ - Behavioural reference: `src/components/form-controls/Select.tsx` (responsive shell).
package/llms.txt CHANGED
@@ -177,9 +177,9 @@ All component documentation is located in the `docs/` folder. The following docu
177
177
  ### FormControls
178
178
  - File: `docs/FormControls.md`
179
179
  - Purpose: Set of form primitives: Input, TextArea, Select, Date, Checkbox, Radio, File, Toggle, Stepper. Access via FormControls.Input, FormControls.Select, etc.
180
- - Key Features: Input (supports text/search/number + prefix/suffix; number maps to numeric text input and clamps via `min`/`max` on blur; search adds icon + clear button), TextArea, **Select** (Floating UI: portalled combobox on desktop with flip/shift positioning; **viewport ≤768px** uses a **bottom sheet** shell with `role="dialog"` / `aria-modal` when a label exists; **sync** `options` with in-panel **search filter**, or **async** via `options={null}` + `onSearch` (debounced); **groups** (`Option.group` sticky headers); **multi** chips with `triggerMaxItems` **+N** overflow, **Select all / Clear all**, **`maxSelect`** cap; optional **`onAddOption`**; combobox + listbox ARIA, **`aria-invalid`** on error, **`aria-controls`** on trigger/search only while open; `name` + hidden input for forms — multi posts comma-joined **`value`s**), Date (dd-mm-yyyy), Checkbox (group-first: options[], CheckboxValue[] for multi-select, onChange(values, e); each option supports `description` and `icon`; `variant="card"` for tile-style options), Radio (group-first: options[], single value, onChange(value, e); each option supports `description` and `icon`; `variant="card"` for tile-style options), File (`variant="button" | "card"`; card variant has dashed drop zone with drag-and-drop; `value: File[]` + `onChange(files, e)`; renders a removable file list with type-aware thumbnail, name, and size), Toggle (switch semantics via checkbox + role="switch"), Stepper; common props label, isRequired, isFluid, error
180
+ - Key Features: Input (supports text/search/number + prefix/suffix; number maps to numeric text input and clamps via `min`/`max` on blur; search adds icon + clear button), TextArea, **Select** (Floating UI: portalled combobox on desktop with flip/shift positioning; **viewport ≤768px** uses a **bottom sheet** shell with `role="dialog"` / `aria-modal` when a label exists; **sync** `options` with in-panel **search filter**, or **async** via `options={null}` + `onSearch` (debounced); **groups** (`Option.group` sticky headers); **multi** chips with `triggerMaxItems` **+N** overflow, **Select all / Clear all**, **`maxSelect`** cap; optional **`onAddOption`**; combobox + listbox ARIA, **`aria-invalid`** on error, **`aria-controls`** on trigger/search only while open; `name` + hidden input for forms — multi posts comma-joined **`value`s**), **Date** (calendar **`Date | null`** + **Cancel/OK** staging; `date-fns` **Locale** + **`dateFormat`**; **Floating UI** desktop popover **~max 400px** wide (viewport-capped) with **`popoverPlacement`**; **≤768px** **bottom sheet** + backdrop/body lock like Select; **month/year subviews** with back + **“Select a month of {yyyy}”** / **“Select a year for {MMMM}”** titles; trigger **`calendar_month`** icon + optional clear; **`minDate`/`maxDate`/`disabledDates`/`disabledDaysOfWeek`**, **`weekStartsOn`**, **`readOnly`**, **`clearable`**, **`name`** → hidden **`yyyy-MM-dd`**, **`onOpen`/`onClose`**), Checkbox (group-first: options[], CheckboxValue[] for multi-select, onChange(values, e); each option supports `description` and `icon`; `variant="card"` for tile-style options), Radio (group-first: options[], single value, onChange(value, e); each option supports `description` and `icon`; `variant="card"` for tile-style options), File (`variant="button" | "card"`; card variant has dashed drop zone with drag-and-drop; `value: File[]` + `onChange(files, e)`; renders a removable file list with type-aware thumbnail, name, and size), Toggle (switch semantics via checkbox + role="switch"), Stepper; common props label, isRequired, isFluid, error
181
181
  - Types: InputProps, **Option** (preferred), **SelectOption** (deprecated alias of Option), **SelectValue**, SelectProps, TextAreaProps, CheckboxProps, CheckboxOption, CheckboxValue, FileProps, FileVariant, RadioProps, RadioOption, RadioValue, ToggleProps, DateProps, FormControlsStepperProps
182
- - Theming: Public CSS custom property `--cp-form-control-radius` (default `var(--radius-large)` = 12px) controls corner radius for Input, TextArea, Stepper, Select trigger + open dropdown corners, Date day/month/year segments, File (outline trigger, drop zone, in-card CTA span, file list rows), and Radio/Checkbox `variant="card"` tiles. Override on `:root` (or any wrapper / inline `style`) after importing `cleanplate/dist/index.css` to retheme just form fields. Prefer this over overriding the underlying `--radius-large` design token, which affects every "large radius" surface in the framework.
182
+ - Theming: Public CSS custom property `--cp-form-control-radius` (default `var(--radius-large)` = 12px) controls corner radius for Input, TextArea, Stepper, Select trigger + open dropdown corners, Date trigger + calendar panel shell, File (outline trigger, drop zone, in-card CTA span, file list rows), and Radio/Checkbox `variant="card"` tiles. Override on `:root` (or any wrapper / inline `style`) after importing `cleanplate/dist/index.css` to retheme just form fields. Prefer this over overriding the underlying `--radius-large` design token, which affects every "large radius" surface in the framework.
183
183
  - Related Components: Pills (Input), Pagination (Select), Container, Button
184
184
 
185
185
  ### Toast Component
package/package.json CHANGED
@@ -1,24 +1,27 @@
1
1
  {
2
2
  "name": "cleanplate",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "CleanPlate - A Headless React UI Framework",
5
5
  "files": [
6
6
  "dist",
7
7
  "docs",
8
8
  "llms.txt",
9
- "AGENTS.md"
9
+ "AGENTS.md",
10
+ "CHANGELOG.md"
10
11
  ],
11
12
  "main": "dist/index.js",
12
13
  "module": "dist/index.es.js",
13
14
  "types": "dist/index.d.ts",
14
15
  "scripts": {
15
- "storybook": "storybook dev -p 6001",
16
- "build-storybook": "storybook build",
17
16
  "build-package": "npm run generate-icons && rollup -c && npm run build-types",
17
+ "build-storybook": "storybook build",
18
18
  "build-types": "tsc --emitDeclarationOnly",
19
- "type-check": "tsc --noEmit",
19
+ "generate-icons": "node scripts/generate-icons.js",
20
20
  "generate-llms-txt": "storybook-llms-extractor --config llms.config.js",
21
- "generate-icons": "node scripts/generate-icons.js"
21
+ "storybook": "storybook dev -p 6001",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "type-check": "tsc --noEmit"
22
25
  },
23
26
  "repository": {
24
27
  "type": "git",
@@ -36,7 +39,8 @@
36
39
  },
37
40
  "homepage": "https://cleanplate.sivadass.in",
38
41
  "dependencies": {
39
- "@floating-ui/react": "^0.27.16"
42
+ "@floating-ui/react": "^0.27.16",
43
+ "date-fns": "^4.1.0"
40
44
  },
41
45
  "devDependencies": {
42
46
  "@babel/preset-react": "^7.23.3",
@@ -50,13 +54,20 @@
50
54
  "@storybook/addon-interactions": "^7.5.3",
51
55
  "@storybook/addon-links": "^7.5.3",
52
56
  "@storybook/blocks": "^7.5.3",
57
+ "@storybook/builder-vite": "^7.5.3",
53
58
  "@storybook/react": "^7.5.3",
54
59
  "@storybook/react-vite": "^7.5.3",
55
60
  "@storybook/testing-library": "^0.2.2",
61
+ "@testing-library/jest-dom": "^6.6.3",
62
+ "@testing-library/react": "^16.3.0",
63
+ "@testing-library/user-event": "^14.6.1",
56
64
  "@types/node": "^25.0.9",
57
65
  "@types/react": "^19.2.8",
58
66
  "@types/react-dom": "^19.2.3",
67
+ "@vitejs/plugin-react": "^4.7.0",
68
+ "@vitest/ui": "^3.2.0",
59
69
  "cheerio": "^1.2.0",
70
+ "jsdom": "^26.1.0",
60
71
  "node-fetch": "^2.7.0",
61
72
  "prop-types": "^15.8.1",
62
73
  "react": "^18.2.0",
@@ -66,7 +77,9 @@
66
77
  "rollup-plugin-postcss": "^4.0.2",
67
78
  "sass": "^1.72.0",
68
79
  "storybook": "^7.5.3",
69
- "typescript": "^5.9.3"
80
+ "typescript": "^5.9.3",
81
+ "vite": "^5.4.11",
82
+ "vitest": "^3.2.0"
70
83
  },
71
84
  "peerDependencies": {
72
85
  "react": ">=18",