@nadicodeai/ui 6.0.1 → 6.1.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 (63) hide show
  1. package/dist/components/action-menu.d.ts +8 -0
  2. package/dist/components/action-menu.d.ts.map +1 -0
  3. package/dist/components/action-menu.js +8 -0
  4. package/dist/components/card.d.ts +1 -1
  5. package/dist/components/card.d.ts.map +1 -1
  6. package/dist/components/card.js +5 -3
  7. package/dist/components/chart-breakdown-table.d.ts +3 -2
  8. package/dist/components/chart-breakdown-table.d.ts.map +1 -1
  9. package/dist/components/chart-breakdown-table.js +13 -9
  10. package/dist/components/chart-bullet-bar.d.ts +13 -12
  11. package/dist/components/chart-bullet-bar.d.ts.map +1 -1
  12. package/dist/components/chart-bullet-bar.js +16 -36
  13. package/dist/components/chart-kpi-stat.d.ts +26 -15
  14. package/dist/components/chart-kpi-stat.d.ts.map +1 -1
  15. package/dist/components/chart-kpi-stat.js +28 -4
  16. package/dist/components/chart-time-series-layout.d.ts +6 -0
  17. package/dist/components/chart-time-series-layout.d.ts.map +1 -0
  18. package/dist/components/chart-time-series-layout.js +6 -0
  19. package/dist/components/chart-time-series.d.ts +6 -2
  20. package/dist/components/chart-time-series.d.ts.map +1 -1
  21. package/dist/components/chart-time-series.js +27 -9
  22. package/dist/components/chart.js +1 -1
  23. package/dist/components/collection-filters.d.ts +28 -0
  24. package/dist/components/collection-filters.d.ts.map +1 -0
  25. package/dist/components/collection-filters.js +54 -0
  26. package/dist/components/collection-scope.d.ts +15 -0
  27. package/dist/components/collection-scope.d.ts.map +1 -0
  28. package/dist/components/collection-scope.js +7 -0
  29. package/dist/components/collection-toolbar.d.ts +10 -0
  30. package/dist/components/collection-toolbar.d.ts.map +1 -0
  31. package/dist/components/collection-toolbar.js +4 -0
  32. package/dist/components/settings-facts.d.ts +28 -0
  33. package/dist/components/settings-facts.d.ts.map +1 -0
  34. package/dist/components/settings-facts.js +7 -0
  35. package/dist/components/settings-section.d.ts +5 -5
  36. package/dist/components/settings-section.d.ts.map +1 -1
  37. package/dist/components/settings-section.js +6 -11
  38. package/dist/components/sidebar.d.ts +4 -1
  39. package/dist/components/sidebar.d.ts.map +1 -1
  40. package/dist/components/sidebar.js +3 -3
  41. package/dist/components/table-layouts.d.ts +22 -0
  42. package/dist/components/table-layouts.d.ts.map +1 -0
  43. package/dist/components/table-layouts.js +20 -0
  44. package/dist/components/table.d.ts +15 -2
  45. package/dist/components/table.d.ts.map +1 -1
  46. package/dist/components/table.js +8 -4
  47. package/dist/eslint/rules/jsx-class-utility.js +44 -12
  48. package/dist/eslint/rules/no-resting-settings-control.js +15 -13
  49. package/dist/eslint/rules/no-shadcn-appearance-override.js +189 -36
  50. package/dist/eslint/rules/shadcn-composition.js +48 -3
  51. package/dist/hooks/use-confirm-action.d.ts +0 -6
  52. package/dist/hooks/use-confirm-action.d.ts.map +1 -1
  53. package/dist/hooks/use-confirm-action.js +5 -12
  54. package/dist/index.d.ts +5 -0
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +5 -0
  57. package/dist/lib/use-copy-to-clipboard.d.ts +0 -41
  58. package/dist/lib/use-copy-to-clipboard.d.ts.map +1 -1
  59. package/dist/lib/use-copy-to-clipboard.js +6 -15
  60. package/docs/component-classification.md +3 -2
  61. package/docs/contract.md +79 -8
  62. package/docs/product-compositions.md +14 -11
  63. package/package.json +3 -2
@@ -19,8 +19,9 @@ copy, and behavior.
19
19
 
20
20
  | Component | Classification | Built on | Required states | Package-owned accessibility | Fixture |
21
21
  | --- | --- | --- | --- | --- | --- |
22
- | `SettingsSection` | Net-new NadicodeAI product composition. | shadcn `FieldGroup` plus standard section markup. | header with optional actions; field group content. | section structure; no form behavior. | `../tests/guards/product-compositions.test.ts` |
23
- | `SettingsField` | Net-new NadicodeAI product composition. | shadcn `Field`, `FieldLabel`, `FieldDescription`, and `FieldError`. | valid and invalid field rows; disabled rows. | Label `htmlFor`; render props receive control attributes; element controls require an explicit matching `id` and described-by wiring. | `../tests/guards/product-compositions.test.ts` |
22
+ | `ActionMenu` | Canonical record-action composition. | shadcn `Button` and `DropdownMenu`. | closed, open, keyboard selection, focus return. | Required accessible trigger name; inherited menu mechanics. | `../src/components/action-menu.test.tsx` |
23
+ | `SettingsSection` | NadicodeAI product composition. | shadcn Card slots, Separator, and FieldGroup. | header, field group, and divided action footer. | Section structure; consumer owns the form transaction. | `../src/components/settings-section.test.tsx` |
24
+ | `SettingsField` | NadicodeAI product composition. | shadcn Field, FieldLabel, FieldDescription, and FieldError. | valid, invalid, required, and disabled field rows. | Render callback supplies the control's label and message associations in server and client components. | `../src/components/settings-section.test.tsx` |
24
25
  | `FeedbackState` | Net-new central product state composition adapted from shadcn empty-state patterns. | shadcn `Empty` and lucide status icons. | `empty`, `loading`, `saving`, `error`, `permission`, `offline`, `no-results`, `fatal`. | `role="status"` for loading/saving; `role="alert"` for error, permission, offline, and fatal. | `../tests/guards/product-compositions.test.ts` |
25
26
 
26
27
  ## App-Owned Boundaries
package/docs/contract.md CHANGED
@@ -27,6 +27,9 @@ Physical role, not content importance, chooses depth:
27
27
  work chooses it explicitly.
28
28
  - `Card surface="plain"` is the explicit structural/auth/website escape and
29
29
  carries no elevation.
30
+ - `Card surface="outlined"` is a flat panel with a single semantic border and
31
+ compact corners; it carries no elevation ring or shadow. Bounded fact cells
32
+ use it inside resting record sections. Portal's kit keeps the resting default.
30
33
  - Tooltip, menu, popover, select, combobox, navigation popup, hover card,
31
34
  chart tooltip, and toast roots own `nc-elevation-floating` internally.
32
35
  - Dialog, alert dialog, drawer, and sheet roots own `nc-elevation-modal`
@@ -64,11 +67,36 @@ transparent and unframed because the Card already owns containment.
64
67
 
65
68
  ### Tables
66
69
 
67
- `Table` owns the native table structure, solid semantic background, horizontal
68
- overflow, and one compact density: 36px header rows and 40px body rows. Consumers
70
+ `Table` owns the native table structure, solid semantic background, an overflow
71
+ safety boundary, and one compact density: 36px header rows and 40px body rows. Consumers
69
72
  compose `TableHeader`, `TableBody`, `TableRow`, `TableHead`, and `TableCell`; they
70
73
  do not replace table layout with grid or flex, hide the header to create another
71
- presentation, or reconstruct the native semantics with ARIA.
74
+ presentation, or reconstruct the native semantics with ARIA. Portal collections
75
+ must fit their available width without horizontal scrolling: preserve identity
76
+ and actions in columns and place supporting facts in native detail rows before
77
+ the full schema becomes cramped. Test the table container itself, not only the
78
+ document width; retaining the overflow safety boundary must not conceal a
79
+ layout defect.
80
+
81
+ `CollectionScope` chooses the parent of one record collection. It places the
82
+ scope selector and optional detail action above the collection toolbar. Empty
83
+ parents stay in the selector. Apps bind authorized options and URL state; clearing
84
+ record filters preserves the parent scope. Parent details belong on their detail
85
+ page, not in repeated panels surrounding identical child tables.
86
+
87
+ `BreakdownTable` owns its responsive comparison layout: identity and value stay
88
+ in the main row; share moves into a labeled detail row when space is tight.
89
+ Its caption names the table. Callers supply data and labels, not column-hiding CSS.
90
+
91
+ ### Record action menus
92
+
93
+ `ActionMenu` is the shared three-dot composition of `Button` and `DropdownMenu`:
94
+ a ghost icon trigger, horizontal ellipsis, and end-aligned popup. It inherits the
95
+ menu's glass, elevation, motion, keyboard behavior, and focus return. Supply
96
+ `label` as a localized, record-specific accessible name; `triggerId` supports
97
+ focus return from an app-owned confirmation, and `children` supplies menu items.
98
+ Apps own action selection, permission, placement, and confirmation. Reuse this
99
+ composition instead of drawing another trigger or popup.
72
100
 
73
101
  ## Status Vocabulary
74
102
 
@@ -121,12 +149,15 @@ fundamental `Card` with explicit `visual`, `name`, `job`, `status`, `meta`,
121
149
  and `action` slots and owns presentation only; when it is the page identity,
122
150
  the `name` slot carries the page's `h1`. The app owns Agent data, recipe
123
151
  assignment, status grammar, routing, and actions; it assigns a recipe
124
- explicitly and never infers or randomizes one from a free-form role, and an
125
- Agent that is a recognizable content object renders through `AgentCard`. There is no `AgentGlyph`,
152
+ explicitly and never infers or randomizes one from a free-form role.
153
+ When the product chooses a card presentation, use `AgentCard`; registry cells,
154
+ membership rows, and compact detail headers compose the shared `AgentVisual`
155
+ within the structure their reading task requires. An Agent's presence does not
156
+ by itself choose a card layout. There is no `AgentGlyph`,
126
157
  `AgentRow`, `KpiCard`, or product-domain `agent` object prop in the shared
127
158
  package.
128
159
 
129
- - **Standard components, not app-owned product features.** This package ships primitives, standard UI components, assistant-ui compositions, brand adapters, React adapters, reusable sections, and presentational product components. It must not ship app-specific feature/use-case screens or names such as operator-login, portal activation, customer credential control, or customer management. Generic data tables, command palettes, and chart cards are app-owned shadcn registry adaptations. The source-backed `chart-*` package surface is the plan-approved exception per issue #166; chart cards remain app-owned. Every data-shaped chart exposes an equivalent non-visual data alternative. A component whose complete value is already available in visible text or `aria-valuetext` does not add a redundant table.
160
+ - **Standard components, not app-owned product features.** This package ships primitives, standard UI components, assistant-ui compositions, brand adapters, React adapters, reusable sections, and presentational product components. It must not ship app-specific feature/use-case screens or names such as operator-login, portal activation, customer credential control, or customer management. Domain registries, command search providers, and chart dashboards bind app data and routes in the app; that binding is not a reason to copy reusable presentation. Portal's DataTable owns its Next.js query and registry protocol once, while consuming the shared UI foundation. Product-independent compositions belong here with a real consumer. The source-backed `chart-*` package surface is the plan-approved exception per issue #166; apps select charts and bind their titles, data, and navigation. Every data-shaped chart exposes an equivalent non-visual data alternative. A component whose complete value is already available in visible text or `aria-valuetext` does not add a redundant table.
130
161
  - **Auth routes are consumer-owned shadcn block work.** Login, signup, OTP, two-factor, magic-link, and provider-button flows start from the selected shadcn block/example in the consuming app, with app-owned Better Auth behavior. Do not ship generic auth, signup, OTP, federated-login, or provider abstractions from this package unless a later explicit boundary decision replaces the selected shadcn block.
131
162
  - **Reusable sections and compositions live here after proof.** Bento grids, media mounts, demo surfaces, page frames, section intros, CTA bands, proof slots, benefits grids, generic shells, and homepage/use-case sections belong in `@nadicodeai/ui` when a second concrete consumer, a plan-approved shared component, or a named validation slice proves the package boundary. Website, portal, and sibling Nadia routes pass data and media children into existing compositions instead of rebuilding layout locally.
132
163
  - **Brand renderers live here for React consumers.** Logo geometry, asset generation, and usage semantics are owned by [`packages/design-system/DESIGN.md`, "Brand media authority"](../../design-system/DESIGN.md#brand-media-authority). `BrandLockup` supplies the approved horizontal lockup. `BrandMark` serves tight spaces and `BrandWordmark` serves placements where the name must read by itself. All three render the package's public neutral geometry seam with React-scoped SVG ids, dynamic theme paint, and accessible names. Consuming routes use these adapters; they never import raw logo assets, draw brand SVG inline, mask or recolor assets, or create another lockup rule.
@@ -135,17 +166,57 @@ package.
135
166
 
136
167
  ## Accessibility Invariant
137
168
 
138
- **Tier-1 accessibility is tested, browser-free.** Every rendering component test uses the package `expectAccessible` helper; the coverage guard derives the applicable test set and fails omissions. The jsdom tier is structural: rendered contrast, landmark context, focus, and keyboard behavior belong to real-browser Playwright coverage. The shared library ESLint configuration is the executable authority for static JSX accessibility rules, and the repository quality doctrine owns their policy; this contract does not copy the rule inventory.
169
+ **Tier-1 accessibility is tested, browser-free.** Rendering component tests use the package `expectAccessible` helper to check the rendered DOM. The jsdom tier is structural: rendered contrast, landmark context, focus, and keyboard behavior belong to real-browser Playwright coverage. The shared library ESLint configuration is the executable authority for static JSX accessibility rules, and the repository quality doctrine owns their policy; this contract does not copy the rule inventory.
139
170
 
140
171
  ## Reusable Sections
141
172
 
142
173
  The source tree, barrels, and package exports own the current reusable section vocabulary. When a page needs a variation, extend the owning source component with a small typed prop or slot; do not fork the layout in a consumer or document a second component inventory here.
143
174
 
175
+ `KpiStatGroup` owns the metric strip, responsive tiles, and link treatment; `KpiStat` owns its value, note, delta, and decorative trend. Apps supply metrics and bind links through `render`. Time-series charts expose `size`; their lightweight layout module also sizes deferred placeholders, so consumers never select internal chart elements.
176
+
177
+ `CollectionToolbar` owns the collection-control layout: compact filters at the
178
+ leading edge, a flexible search field, and trailing actions. Its slot order is
179
+ also the reading and focus order, including when controls wrap. Consumers supply
180
+ existing controls and own their query state; they do not set independent search
181
+ widths or align filters to table columns. `CollectionFilters` owns the controlled
182
+ field/value picker and applied-filter chips; callers supply options, localized
183
+ copy, and callbacks. The component owns discovery, edit/remove, keyboard focus,
184
+ and empty search results. It does not own routing or fetch state.
185
+
186
+ `SettingsFactsSection` owns a named record or settings reading section: its
187
+ heading and optional action, header separator, and bounded responsive fact
188
+ cells in two equal columns, stacked on compact screens. Consumers supply labels,
189
+ values, an optional contextual footer, and a Card surface; paragraph facts take a full row. The stable heading remains a programmatic focus target
190
+ when an editor closes. Keep fact labels, order, and cells stable when data is
191
+ missing: null and undefined values use the required localized
192
+ `missingValueLabel`, while zero remains a value. Consumers do not filter out
193
+ unknown facts or replace them with indefinite loading skeletons. Editable
194
+ controls remain in `SettingsSection`.
195
+
196
+ `SettingsSection` composes Card's named header, divider, FieldGroup body, and
197
+ optional divided `footer` for local save actions and feedback. The caller owns
198
+ the form transaction and controls; the section owns their shared geometry.
199
+ Header `actions` are optional supporting commands, distinct from footer submission.
200
+ `SettingsField` uses one render callback in server and client components. Spread
201
+ its `controlProps` onto the control to retain the visible label, descriptions,
202
+ error association, and disabled/required state; do not wire another copy by hand.
203
+
204
+ `TableDetailRow` keeps supporting collection facts readable at compact widths
205
+ inside a native full-width table cell. It shares the owning column labels and
206
+ values rather than requiring another responsive cell implementation. Identity
207
+ and status retain their column headers. Missing values retain their place.
208
+ `Table compactDetails` and `TableDetailRow layout` share `tableCompactLayouts`:
209
+ `standard` retains full columns at 768px of container width, `wide` at 1024px,
210
+ and `spacious` at 1152px for schemas with additional operational columns.
211
+ The same owner switches column visibility, detail visibility, and row boundaries.
212
+ Two supporting facts use two columns; additional facts can use three when they fit.
213
+ The cell renderer supplies the value, leaving the label to the detail row.
214
+
144
215
  ## Consumer Boundary
145
216
 
146
217
  Consumers own routing, auth, app data, server actions, runtime construction and adapters, permission decisions, analytics, and app-specific copy. The package owns reusable React presentation and the public Agent UI dependency boundary. Agent state and behavior come through the Agents interface; non-React and TUI contracts belong to their consuming products.
147
218
 
148
- App source composes layout, data, behavior, and semantic content around package components. It does not restyle an imported component root: appearance changes enter through the component's typed variant or are added to the owning package component. App `className` values on package components are limited to structural layout and sizing. App source uses semantic roles such as `bg-background` and `text-foreground`; canonical `nc-*` color utilities stay behind package-owned primitives such as `BrandField`. Raw Tailwind palette colors are not available to anyone: the generated theme clears the `--color-*` namespace, so `bg-red-500` produces no CSS and `better-tailwindcss/no-unknown-classes` reports it. Visible controls come from `@nadicodeai/ui`, while hidden inputs remain valid form transport. The root ESLint rules `nadicodeai/no-shadcn-appearance-override` and `nadicodeai/no-native-visible-control` enforce the rest of this boundary; each takes a `packageOwnedPrimitives` option (`"exempt"` by default, `"lint"` to hold this package's own source to the same rule).
219
+ App source composes layout, data, behavior, and semantic content around package components. It does not restyle an imported component root: appearance changes enter through the component's typed variant or are added to the owning package component. App `className` values on package components arrange and size the component root. Descendant `data-slot` selectors are not a public styling API; internal spacing, type, and sizing belong to the shared component, enforced by `nadicodeai/no-shadcn-appearance-override`. App source uses semantic roles such as `bg-background` and `text-foreground`; canonical `nc-*` color utilities stay behind package-owned primitives such as `BrandField`. Raw Tailwind palette colors are not available to anyone: the generated theme clears the `--color-*` namespace, so `bg-red-500` produces no CSS and `better-tailwindcss/no-unknown-classes` reports it. Visible controls come from `@nadicodeai/ui`, while hidden inputs remain valid form transport. The root ESLint rules `nadicodeai/no-shadcn-appearance-override` and `nadicodeai/no-native-visible-control` enforce the rest of this boundary; each takes a `packageOwnedPrimitives` option (`"exempt"` by default, `"lint"` to hold this package's own source to the same rule).
149
220
 
150
221
  When this package is read from an installed npm package, follow the [consumer setup guide](consuming-cross-repo.md) for setup and public import paths. The styling invariant above remains the authority for component implementation.
151
222
 
@@ -1,13 +1,10 @@
1
1
  # Product Compositions
2
2
 
3
- U4 adds the first shared product compositions for NadicodeAI admin, settings, and agent-work surfaces. These components are presentational only: consumers own routing, persistence, server actions, mutations, analytics, auth providers, permissions, and product-specific page copy.
3
+ Shared product compositions own repeatable presentation and interaction. Consumers bind routing, persistence, permissions, and product copy. See the [component contract](contract.md) for each family's ownership.
4
4
 
5
- When first-party shadcn or assistant-ui registry source already covers the same
6
- generic product UI, use that registry item in the consuming app instead of
7
- adding a parallel NadicodeAI package API. Data tables, command palettes, and
8
- chart cards follow this rule: use `@shadcn/data-table-demo`,
9
- `@shadcn/command-dialog`, `@shadcn/chart`, or the relevant `@shadcn/chart-*`
10
- block/example as the source of truth.
5
+ Check first-party shadcn or assistant-ui registry patterns before adding a
6
+ composition. Once adapted, reuse its maintained owner; do not assemble the same
7
+ registry example again for each page.
11
8
 
12
9
  Import components through the wildcard component subpath after build:
13
10
 
@@ -19,12 +16,13 @@ Fixtures live in:
19
16
 
20
17
  - [`../tests/guards/product-compositions.test.ts`](../tests/guards/product-compositions.test.ts)
21
18
  - [`../tests/guards/product-compositions-ssr.test.ts`](../tests/guards/product-compositions-ssr.test.ts)
19
+ - [`../src/components/settings-section.test.tsx`](../src/components/settings-section.test.tsx)
22
20
 
23
21
  ## Boundaries
24
22
 
25
23
  | Component | Package owns | Consumer owns |
26
24
  | --- | --- | --- |
27
- | `SettingsSection` / `SettingsField` | Horizontal settings layout, `Field` composition, labels, descriptions, errors, deterministic description and error ids, `data-invalid`, and render-prop control wiring. | Form state, validation rules, submission, persistence, settings taxonomy, save/cancel behavior, and explicit control wiring for element children. |
25
+ | `SettingsSection` / `SettingsField` | Header, divided save footer, field layout, labels, descriptions, errors, and control associations. | Form state, validation, submission, persistence, settings taxonomy, and save/cancel behavior. |
28
26
  | `FeedbackState` | Shared empty, loading, saving, error, permission, offline, no-results, and fatal state presentation. | Recovery actions, retry behavior, permission escalation, app-specific state language. |
29
27
 
30
28
  ## SettingsSection
@@ -35,6 +33,7 @@ Use `SettingsSection` and `SettingsField` for horizontal settings rows that need
35
33
  <SettingsSection
36
34
  title="Workspace defaults"
37
35
  description="Shared defaults for agent work."
36
+ footer={<Button type="submit">Save</Button>}
38
37
  >
39
38
  <SettingsField
40
39
  id="review-window"
@@ -44,7 +43,7 @@ Use `SettingsSection` and `SettingsField` for horizontal settings rows that need
44
43
  invalid={Boolean(reviewWindowError)}
45
44
  >
46
45
  {({ controlProps }) => (
47
- <input {...controlProps} value={reviewWindow} onChange={onReviewWindowChange} />
46
+ <Input {...controlProps} value={reviewWindow} onChange={onReviewWindowChange} />
48
47
  )}
49
48
  </SettingsField>
50
49
  </SettingsSection>
@@ -53,11 +52,15 @@ Use `SettingsSection` and `SettingsField` for horizontal settings rows that need
53
52
  | Prop | Purpose |
54
53
  | --- | --- |
55
54
  | `title` / `description` / `actions` | Section header content and right-side action slot. |
55
+ | `footer` | Local Save/Cancel controls and completion feedback. The owning form wraps the section. |
56
56
  | `id` / `label` | Required field identity and accessible label. |
57
57
  | `description` / `error` / `invalid` | Field helper text, error text, and invalid state. |
58
- | `children` | A render function receives `controlProps` for the real control and requires a client-component consumer. An element child renders unchanged and must put an explicit `id` matching the field `id` on its control. |
58
+ | `children` | A render function receives `controlProps` for the real control in server and client components. |
59
59
 
60
- Accessibility: `FieldLabel` uses the field `id` as `htmlFor`. The render-prop form passes `id`, `aria-invalid`, `aria-describedby`, `disabled`, and `required` to the consumer for placement on the real control. Functions cannot cross the React Server Component boundary, so this form requires a client-component consumer. Element children render unchanged; the consumer must put the matching `id` on the control and add `aria-describedby` when needed. Descriptions render with `${id}-description`, and errors render with `${id}-error`.
60
+ Spread `controlProps` onto the real control. SettingsField invokes the callback
61
+ before rendered children cross any client boundary; it does not forward the
62
+ callback to a client component. The [contract](contract.md) owns the field's
63
+ accessibility and state guarantees.
61
64
 
62
65
  ## FeedbackState
63
66
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nadicodeai/ui",
3
- "version": "6.0.1",
3
+ "version": "6.1.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -70,7 +70,7 @@
70
70
  "@assistant-ui/react": "0.15.18",
71
71
  "@assistant-ui/react-markdown": "0.14.14",
72
72
  "@base-ui/react": "^1.8.0",
73
- "@nadicodeai/design-system": "6.0.1",
73
+ "@nadicodeai/design-system": "6.1.0",
74
74
  "@paper-design/shaders": "0.0.80",
75
75
  "class-variance-authority": "^0.7.1",
76
76
  "clsx": "^2.1.1",
@@ -106,6 +106,7 @@
106
106
  "@stryker-mutator/vitest-runner": "10.0.0",
107
107
  "@tailwindcss/postcss": "^4.3.3",
108
108
  "@testing-library/react": "^16.3.3",
109
+ "@testing-library/user-event": "^14.6.7",
109
110
  "@types/react": "19.2.18",
110
111
  "@types/react-dom": "19.2.7",
111
112
  "axe-core": "^4.13.0",