From 26172eb3092e6354d197df709c16ff3ba9d77af6 Mon Sep 17 00:00:00 2001 From: Christoph Mussenbrock Date: Tue, 20 May 2025 16:30:15 +0200 Subject: [PATCH 1/8] docs: add task planning document for form components (task 2.1) --- .../task-planning/task-2.1-form-components.md | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 docs/task-planning/task-2.1-form-components.md diff --git a/docs/task-planning/task-2.1-form-components.md b/docs/task-planning/task-2.1-form-components.md new file mode 100644 index 0000000..0dc14c0 --- /dev/null +++ b/docs/task-planning/task-2.1-form-components.md @@ -0,0 +1,47 @@ +# Task 2.1 Planning: Form Components + +## Overview + +This task involves implementing four form-related components: + +- NumberInput +- Select +- Checkbox +- RadioGroup + +These components will follow the established design patterns in the existing codebase, utilizing Shadcn UI as the foundation and conforming to the accessibility requirements. + +## Task Breakdown + +| Task Description | Definition of Done (DoD) | Status | +| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------ | +| Set up directory structure for each component | All four component directories created with appropriate files (component, types, tests, stories) | open | +| Implement NumberInput component | Component renders correctly and accepts all required props; Unit tests pass; a11y tests pass | open | +| Implement Select component | Component renders correctly and accepts all required props; Unit tests pass; a11y tests pass | open | +| Implement Checkbox component | Component renders correctly and accepts all required props; Unit tests pass; a11y tests pass | open | +| Implement RadioGroup component | Component renders correctly and accepts all required props; Unit tests pass; a11y tests pass | open | +| Update barrel exports in index.ts | All components are properly exported and accessible from the package's public API | open | +| Create consolidated form story | Story shows all components working together in a cohesive form; All components render correctly with proper styling | open | +| Final review and documentation | All components are properly documented; Code adheres to project standards; No lint errors; All tests pass | open | + +## Implementation Strategy + +### Component Architecture + +- Each component will be implemented following the same pattern as existing components (Button, TextInput) +- Components will be built on top of Shadcn UI primitives +- Each component will have proper TypeScript typing +- Components will include accessibility features + +### Testing Approach + +- Unit tests with Vitest for functionality +- Accessibility tests with axe-core +- Storybook stories to demonstrate all variants and states +- Snapshot tests for visual regression + +## Timeline + +- Estimated completion: 3-4 days +- First 2 days: Implement individual components +- Last 1-2 days: Integration, testing, and documentation From 6ff8d093be920078d219fe3d9a0604f3cac97ab1 Mon Sep 17 00:00:00 2001 From: Christoph Mussenbrock Date: Tue, 20 May 2025 16:30:48 +0200 Subject: [PATCH 2/8] docs: mark task 1.5 as completed in project plan --- docs/project_plan.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/project_plan.md b/docs/project_plan.md index b315299..8e13a58 100644 --- a/docs/project_plan.md +++ b/docs/project_plan.md @@ -34,7 +34,7 @@ A pragmatic breakdown into **four one‑week sprints** plus a preparatory **Spri | 1.2c | Configure and verify Storybook addon‑a11y. | axe‑a11y addon shows zero violations. | ✓ | | 1.3 | Add global theme bridging (`theme.css` ↔ DaisyUI). | Cypress visual diff (light/dark) matches golden images. | ✓ | | 1.4 | Create first **AuthShell** layout with logo slot. | Rendered via Storybook; Playwright snapshot approved. | ✓ | -| 1.5 | Document design tokens (`DESIGN_TOKENS.md`). | File exists; CI step `tokens-check` verifies presence of each CSS var. | PR | +| 1.5 | Document design tokens (`DESIGN_TOKENS.md`). | File exists; CI step `tokens-check` verifies presence of each CSS var. | ✓ | --- From 0e17eac7a973a4cc233507b5013174203e7cf699 Mon Sep 17 00:00:00 2001 From: Christoph Mussenbrock Date: Tue, 20 May 2025 16:35:21 +0200 Subject: [PATCH 3/8] feat: set up directory structure and initial implementation for form components --- .../primitives/Checkbox/Checkbox.tsx | 44 ++++++ .../components/primitives/Checkbox/index.ts | 2 + .../components/primitives/Checkbox/types.ts | 12 ++ .../primitives/NumberInput/NumberInput.tsx | 42 +++++ .../primitives/NumberInput/index.ts | 2 + .../primitives/NumberInput/types.ts | 16 ++ .../primitives/RadioGroup/RadioGroup.tsx | 52 +++++++ .../components/primitives/RadioGroup/index.ts | 2 + .../components/primitives/RadioGroup/types.ts | 20 +++ .../components/primitives/Select/Select.tsx | 72 +++++++++ .../src/components/primitives/Select/index.ts | 2 + .../src/components/primitives/Select/types.ts | 26 ++++ .../ui-kit/src/components/primitives/index.ts | 6 +- .../ui-kit/src/components/ui/checkbox.tsx | 41 +++++ .../ui-kit/src/components/ui/radio-group.tsx | 42 +++++ packages/ui-kit/src/components/ui/select.tsx | 145 ++++++++++++++++++ 16 files changed, 525 insertions(+), 1 deletion(-) create mode 100644 packages/ui-kit/src/components/primitives/Checkbox/Checkbox.tsx create mode 100644 packages/ui-kit/src/components/primitives/Checkbox/index.ts create mode 100644 packages/ui-kit/src/components/primitives/Checkbox/types.ts create mode 100644 packages/ui-kit/src/components/primitives/NumberInput/NumberInput.tsx create mode 100644 packages/ui-kit/src/components/primitives/NumberInput/index.ts create mode 100644 packages/ui-kit/src/components/primitives/NumberInput/types.ts create mode 100644 packages/ui-kit/src/components/primitives/RadioGroup/RadioGroup.tsx create mode 100644 packages/ui-kit/src/components/primitives/RadioGroup/index.ts create mode 100644 packages/ui-kit/src/components/primitives/RadioGroup/types.ts create mode 100644 packages/ui-kit/src/components/primitives/Select/Select.tsx create mode 100644 packages/ui-kit/src/components/primitives/Select/index.ts create mode 100644 packages/ui-kit/src/components/primitives/Select/types.ts create mode 100644 packages/ui-kit/src/components/ui/checkbox.tsx create mode 100644 packages/ui-kit/src/components/ui/radio-group.tsx create mode 100644 packages/ui-kit/src/components/ui/select.tsx diff --git a/packages/ui-kit/src/components/primitives/Checkbox/Checkbox.tsx b/packages/ui-kit/src/components/primitives/Checkbox/Checkbox.tsx new file mode 100644 index 0000000..74484fa --- /dev/null +++ b/packages/ui-kit/src/components/primitives/Checkbox/Checkbox.tsx @@ -0,0 +1,44 @@ +import * as React from 'react'; +import { cn } from '@/utils/cn'; +import { Checkbox as ShadcnCheckbox } from '@/components/ui/checkbox'; +import { CheckboxProps } from './types'; + +export const Checkbox = React.forwardRef( + ( + { label, description, error, className, disabled, ...props }, + ref + ) => { + return ( +
+
+ + {label && ( + + )} +
+ {description && !error && ( +

{description}

+ )} + {error && ( +

{error}

+ )} +
+ ); + } +); + +Checkbox.displayName = 'Checkbox'; \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/Checkbox/index.ts b/packages/ui-kit/src/components/primitives/Checkbox/index.ts new file mode 100644 index 0000000..f601b0e --- /dev/null +++ b/packages/ui-kit/src/components/primitives/Checkbox/index.ts @@ -0,0 +1,2 @@ +export * from './Checkbox'; +export * from './types'; \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/Checkbox/types.ts b/packages/ui-kit/src/components/primitives/Checkbox/types.ts new file mode 100644 index 0000000..d7f6372 --- /dev/null +++ b/packages/ui-kit/src/components/primitives/Checkbox/types.ts @@ -0,0 +1,12 @@ +import { CheckboxProps as ShadcnCheckboxProps } from '@radix-ui/react-checkbox'; + +export interface CheckboxProps extends ShadcnCheckboxProps { + /** Label text displayed next to the checkbox */ + label?: string; + /** Description/help text rendered below */ + description?: string; + /** Marks checkbox as invalid */ + error?: string; + /** Optional CSS class name */ + className?: string; +} \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/NumberInput/NumberInput.tsx b/packages/ui-kit/src/components/primitives/NumberInput/NumberInput.tsx new file mode 100644 index 0000000..7cfd3fd --- /dev/null +++ b/packages/ui-kit/src/components/primitives/NumberInput/NumberInput.tsx @@ -0,0 +1,42 @@ +import * as React from 'react'; +import { Input } from '@/components/ui/input'; +import { cn } from '@/utils/cn'; +import { NumberInputProps } from './types'; + +export const NumberInput = React.forwardRef( + ( + { label, description, error, className, min, max, step = 1, ...props }, + ref + ) => { + return ( +
+ {label && ( + + )} + + {description && !error && ( +

{description}

+ )} + {error && ( +

{error}

+ )} +
+ ); + } +); + +NumberInput.displayName = 'NumberInput'; \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/NumberInput/index.ts b/packages/ui-kit/src/components/primitives/NumberInput/index.ts new file mode 100644 index 0000000..da0aed6 --- /dev/null +++ b/packages/ui-kit/src/components/primitives/NumberInput/index.ts @@ -0,0 +1,2 @@ +export * from './NumberInput'; +export * from './types'; \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/NumberInput/types.ts b/packages/ui-kit/src/components/primitives/NumberInput/types.ts new file mode 100644 index 0000000..d51dc18 --- /dev/null +++ b/packages/ui-kit/src/components/primitives/NumberInput/types.ts @@ -0,0 +1,16 @@ +import { InputProps } from '@/components/ui/input'; + +export interface NumberInputProps extends Omit { + /** Label text displayed above the input */ + label?: string; + /** Description/help text rendered below */ + description?: string; + /** Marks input as invalid */ + error?: string; + /** Minimum value allowed */ + min?: number; + /** Maximum value allowed */ + max?: number; + /** Step value for incrementing/decrementing */ + step?: number; +} \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/RadioGroup/RadioGroup.tsx b/packages/ui-kit/src/components/primitives/RadioGroup/RadioGroup.tsx new file mode 100644 index 0000000..1c47de3 --- /dev/null +++ b/packages/ui-kit/src/components/primitives/RadioGroup/RadioGroup.tsx @@ -0,0 +1,52 @@ +import * as React from 'react'; +import { cn } from '@/utils/cn'; +import { RadioGroup as ShadcnRadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; +import { RadioGroupProps } from './types'; + +export const RadioGroup = React.forwardRef( + ( + { label, description, error, className, options, disabled, ...props }, + ref + ) => { + return ( +
+ {label && ( + + )} + + {options.map((option) => ( +
+ + +
+ ))} +
+ {description && !error && ( +

{description}

+ )} + {error && ( +

{error}

+ )} +
+ ); + } +); + +RadioGroup.displayName = 'RadioGroup'; \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/RadioGroup/index.ts b/packages/ui-kit/src/components/primitives/RadioGroup/index.ts new file mode 100644 index 0000000..aaf3826 --- /dev/null +++ b/packages/ui-kit/src/components/primitives/RadioGroup/index.ts @@ -0,0 +1,2 @@ +export * from './RadioGroup'; +export * from './types'; \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/RadioGroup/types.ts b/packages/ui-kit/src/components/primitives/RadioGroup/types.ts new file mode 100644 index 0000000..03e0e6e --- /dev/null +++ b/packages/ui-kit/src/components/primitives/RadioGroup/types.ts @@ -0,0 +1,20 @@ +import { RadioGroupProps as ShadcnRadioGroupProps } from '@radix-ui/react-radio-group'; + +export interface RadioOption { + value: string; + label: string; + disabled?: boolean; +} + +export interface RadioGroupProps extends ShadcnRadioGroupProps { + /** Label text displayed above the radio group */ + label?: string; + /** Description/help text rendered below */ + description?: string; + /** Marks radio group as invalid */ + error?: string; + /** Array of options for the radio group */ + options: RadioOption[]; + /** Optional CSS class name */ + className?: string; +} \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/Select/Select.tsx b/packages/ui-kit/src/components/primitives/Select/Select.tsx new file mode 100644 index 0000000..44f0701 --- /dev/null +++ b/packages/ui-kit/src/components/primitives/Select/Select.tsx @@ -0,0 +1,72 @@ +import * as React from 'react'; +import { cn } from '@/utils/cn'; +import { + Select as ShadcnSelect, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { SelectProps } from './types'; + +export const Select = React.forwardRef( + ( + { + label, + description, + error, + className, + placeholder, + options, + value, + onValueChange, + disabled, + ...props + }, + ref + ) => { + return ( +
+ {label && ( + + )} + + + + + + {options.map((option) => ( + + {option.label} + + ))} + + + {description && !error && ( +

{description}

+ )} + {error && ( +

{error}

+ )} +
+ ); + } +); + +Select.displayName = 'Select'; \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/Select/index.ts b/packages/ui-kit/src/components/primitives/Select/index.ts new file mode 100644 index 0000000..8abb30b --- /dev/null +++ b/packages/ui-kit/src/components/primitives/Select/index.ts @@ -0,0 +1,2 @@ +export * from './Select'; +export * from './types'; \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/Select/types.ts b/packages/ui-kit/src/components/primitives/Select/types.ts new file mode 100644 index 0000000..0f35e12 --- /dev/null +++ b/packages/ui-kit/src/components/primitives/Select/types.ts @@ -0,0 +1,26 @@ +import { SelectProps as ShadcnSelectProps } from '@radix-ui/react-select'; + +export interface SelectOption { + value: string; + label: string; + disabled?: boolean; +} + +export interface SelectProps extends ShadcnSelectProps { + /** Label text displayed above the select */ + label?: string; + /** Description/help text rendered below */ + description?: string; + /** Marks select as invalid */ + error?: string; + /** Placeholder text when no option is selected */ + placeholder?: string; + /** Array of options for the select */ + options: SelectOption[]; + /** Current value of the select */ + value?: string; + /** Callback when value changes */ + onValueChange?: (value: string) => void; + /** Optional CSS class name */ + className?: string; +} \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/index.ts b/packages/ui-kit/src/components/primitives/index.ts index 1332698..937c488 100644 --- a/packages/ui-kit/src/components/primitives/index.ts +++ b/packages/ui-kit/src/components/primitives/index.ts @@ -1,2 +1,6 @@ export * from './Button' -export * from './TextInput' \ No newline at end of file +export * from './TextInput' +export * from './NumberInput' +export * from './Select' +export * from './Checkbox' +export * from './RadioGroup' \ No newline at end of file diff --git a/packages/ui-kit/src/components/ui/checkbox.tsx b/packages/ui-kit/src/components/ui/checkbox.tsx new file mode 100644 index 0000000..1976d3b --- /dev/null +++ b/packages/ui-kit/src/components/ui/checkbox.tsx @@ -0,0 +1,41 @@ +"use client" + +import * as React from "react" +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import { cn } from "@/utils/cn" + +const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + + + +)) +Checkbox.displayName = CheckboxPrimitive.Root.displayName + +export { Checkbox } \ No newline at end of file diff --git a/packages/ui-kit/src/components/ui/radio-group.tsx b/packages/ui-kit/src/components/ui/radio-group.tsx new file mode 100644 index 0000000..c7786a0 --- /dev/null +++ b/packages/ui-kit/src/components/ui/radio-group.tsx @@ -0,0 +1,42 @@ +"use client" + +import * as React from "react" +import * as RadioGroupPrimitive from "@radix-ui/react-radio-group" +import { cn } from "@/utils/cn" + +const RadioGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => { + return ( + + ) +}) +RadioGroup.displayName = RadioGroupPrimitive.Root.displayName + +const RadioGroupItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => { + return ( + + +
+ + + ) +}) +RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName + +export { RadioGroup, RadioGroupItem } \ No newline at end of file diff --git a/packages/ui-kit/src/components/ui/select.tsx b/packages/ui-kit/src/components/ui/select.tsx new file mode 100644 index 0000000..0823d39 --- /dev/null +++ b/packages/ui-kit/src/components/ui/select.tsx @@ -0,0 +1,145 @@ +"use client" + +import * as React from "react" +import * as SelectPrimitive from "@radix-ui/react-select" +import { cn } from "@/utils/cn" + +const Select = SelectPrimitive.Root + +const SelectGroup = SelectPrimitive.Group + +const SelectValue = SelectPrimitive.Value + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + {children} + + + + + + +)) +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = "popper", ...props }, ref) => ( + + + + {children} + + + +)) +SelectContent.displayName = SelectPrimitive.Content.displayName + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectLabel.displayName = SelectPrimitive.Label.displayName + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + + + + {children} + +)) +SelectItem.displayName = SelectPrimitive.Item.displayName + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, +} \ No newline at end of file From c7980719e8eea20f66656d80c069b5b5bc1101af Mon Sep 17 00:00:00 2001 From: Christoph Mussenbrock Date: Tue, 20 May 2025 16:35:59 +0200 Subject: [PATCH 4/8] docs: update task status in planning document --- .../task-planning/task-2.1-form-components.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/task-planning/task-2.1-form-components.md b/docs/task-planning/task-2.1-form-components.md index 0dc14c0..804f516 100644 --- a/docs/task-planning/task-2.1-form-components.md +++ b/docs/task-planning/task-2.1-form-components.md @@ -13,16 +13,16 @@ These components will follow the established design patterns in the existing cod ## Task Breakdown -| Task Description | Definition of Done (DoD) | Status | -| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------ | -| Set up directory structure for each component | All four component directories created with appropriate files (component, types, tests, stories) | open | -| Implement NumberInput component | Component renders correctly and accepts all required props; Unit tests pass; a11y tests pass | open | -| Implement Select component | Component renders correctly and accepts all required props; Unit tests pass; a11y tests pass | open | -| Implement Checkbox component | Component renders correctly and accepts all required props; Unit tests pass; a11y tests pass | open | -| Implement RadioGroup component | Component renders correctly and accepts all required props; Unit tests pass; a11y tests pass | open | -| Update barrel exports in index.ts | All components are properly exported and accessible from the package's public API | open | -| Create consolidated form story | Story shows all components working together in a cohesive form; All components render correctly with proper styling | open | -| Final review and documentation | All components are properly documented; Code adheres to project standards; No lint errors; All tests pass | open | +| Task Description | Definition of Done (DoD) | Status | +| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | -------- | +| Set up directory structure for each component | All four component directories created with appropriate files (component, types, tests, stories) | complete | +| Implement NumberInput component | Component renders correctly and accepts all required props; Unit tests pass; a11y tests pass | working | +| Implement Select component | Component renders correctly and accepts all required props; Unit tests pass; a11y tests pass | open | +| Implement Checkbox component | Component renders correctly and accepts all required props; Unit tests pass; a11y tests pass | open | +| Implement RadioGroup component | Component renders correctly and accepts all required props; Unit tests pass; a11y tests pass | open | +| Update barrel exports in index.ts | All components are properly exported and accessible from the package's public API | open | +| Create consolidated form story | Story shows all components working together in a cohesive form; All components render correctly with proper styling | open | +| Final review and documentation | All components are properly documented; Code adheres to project standards; No lint errors; All tests pass | open | ## Implementation Strategy From d6c1ead2f85fe40d4512dd9cab8a0682abb49c3b Mon Sep 17 00:00:00 2001 From: Christoph Mussenbrock Date: Tue, 20 May 2025 17:27:11 +0200 Subject: [PATCH 5/8] feat: implement form primitives with tests and stories --- .cursor/rules/coding.mdc | 29 +- .cursor/rules/styling_rules.mdc | 7 + components.json | 21 + docs/task-planning/task-2.1.md | 22 + .../task-planning/task-2.1a-shadcn-upgrade.md | 41 + package.json | 5 +- packages/ui-kit/components.json | 21 + packages/ui-kit/package.json | 14 +- .../src/components/FormExample.stories.tsx | 115 +++ .../primitives/Checkbox/Checkbox.stories.tsx | 61 ++ .../primitives/Checkbox/Checkbox.test.tsx | 32 + .../primitives/Checkbox/Checkbox.tsx | 2 +- .../components/primitives/Checkbox/types.ts | 4 +- .../NumberInput/NumberInput.stories.tsx | 61 ++ .../NumberInput/NumberInput.test.tsx | 28 + .../primitives/NumberInput/NumberInput.tsx | 2 +- .../primitives/NumberInput/types.ts | 4 +- .../RadioGroup/RadioGroup.stories.tsx | 65 ++ .../primitives/RadioGroup/RadioGroup.test.tsx | 50 ++ .../primitives/RadioGroup/RadioGroup.tsx | 2 +- .../components/primitives/RadioGroup/types.ts | 4 +- .../primitives/Select/Select.stories.tsx | 66 ++ .../primitives/Select/Select.test.tsx | 31 + .../components/primitives/Select/Select.tsx | 2 +- .../src/components/primitives/Select/types.ts | 4 +- .../primitives/TextInput/TextInput.tsx | 20 +- .../components/primitives/TextInput/types.ts | 12 +- packages/ui-kit/src/components/ui/button.tsx | 71 +- .../ui-kit/src/components/ui/checkbox.tsx | 23 +- packages/ui-kit/src/components/ui/input.tsx | 39 +- .../ui-kit/src/components/ui/radio-group.tsx | 12 +- packages/ui-kit/src/components/ui/select.tsx | 88 ++- packages/ui-kit/src/lib/utils.ts | 6 + packages/ui-kit/src/styles/globals.css | 67 +- packages/ui-kit/tailwind.config.js | 127 +-- pnpm-lock.yaml | 733 +++++++++++++++++- src/lib/utils.ts | 6 + 37 files changed, 1692 insertions(+), 205 deletions(-) create mode 100644 components.json create mode 100644 docs/task-planning/task-2.1.md create mode 100644 docs/task-planning/task-2.1a-shadcn-upgrade.md create mode 100644 packages/ui-kit/components.json create mode 100644 packages/ui-kit/src/components/FormExample.stories.tsx create mode 100644 packages/ui-kit/src/components/primitives/Checkbox/Checkbox.stories.tsx create mode 100644 packages/ui-kit/src/components/primitives/Checkbox/Checkbox.test.tsx create mode 100644 packages/ui-kit/src/components/primitives/NumberInput/NumberInput.stories.tsx create mode 100644 packages/ui-kit/src/components/primitives/NumberInput/NumberInput.test.tsx create mode 100644 packages/ui-kit/src/components/primitives/RadioGroup/RadioGroup.stories.tsx create mode 100644 packages/ui-kit/src/components/primitives/RadioGroup/RadioGroup.test.tsx create mode 100644 packages/ui-kit/src/components/primitives/Select/Select.stories.tsx create mode 100644 packages/ui-kit/src/components/primitives/Select/Select.test.tsx create mode 100644 packages/ui-kit/src/lib/utils.ts create mode 100644 src/lib/utils.ts diff --git a/.cursor/rules/coding.mdc b/.cursor/rules/coding.mdc index 9db6045..47b6f8c 100644 --- a/.cursor/rules/coding.mdc +++ b/.cursor/rules/coding.mdc @@ -13,11 +13,24 @@ alwaysApply: true - Tasks are in docs/project_plan.md - Each task will be implemented via a feature branch and a PR to the develop branch. - Always follow the following recipe for implementing tasks: - 1. Start implementing after the user has explicitly told so. - 2. After finishing implementing, perform all necessary tests and check if the DoD for this task is met. - 3. Report on test results and DoD criteria and ask user if a PR should be submitted. - 4. If the user approves submitting a PR, and before PR is submitted, the task is marked with "PR" in docs/project_plan.md. - 5. After PR ist submitted, report to the user and wait for manual instructions. - 6. The user will then review and merge the PR or ask for updates. - 7. Pull the repo again to check if the PR has been merged. - 8. After task is completed (PR merged), the task is marked with a checkmark in docs/project_plan.md + 1. Only start implementing a task after the user has explicitly told so. + 2. Before starting coding, create a task planning document (.md) in the docs/task-planning folder. + 3. The task planning document contains a table with three columns: tasks description, DoD (Definition of Done) and Status. Status is open, working, checking, review, complete. Initially all tasks are "open". + 1. Open = the task hasn't been worked on. + 2. Working = the task is currently being implemented. + 3. Checking = the DoD of the tasks are being checked. + 4. Review = the user is reviewing the result. + 5. complete = the user has approved the result and the task is complete. + 4. After creating the task planning document, let the user review the doc. + 5. After the user has approved the task planning document, implement each task one after the other. + 6. After implementing a task, check the criteria for DoD and report the result to the user. + 7. If DoD is not met, fix the problem until DoD is met. + 8. Before and after each task, update each task in the table with the right status. + 9. After finishing implementing, perform all necessary tests and check if the DoD for this task is met. + 10. Report on test results and DoD criteria and ask user if a PR should be submitted. + 11. If the user approves submitting a PR, and before PR is submitted, the task is marked with "PR" in docs/project_plan.md. + 12. After PR ist submitted, report to the user and wait for manual instructions. + 13. The user will then review and merge the PR or ask for updates. + 14. Pull the repo again to check if the PR has been merged. + 15. After task is completed (PR merged), the task is marked with a checkmark in docs/project_plan.md. This change does not warrant a separate PR, it will be included in the next PR. Just do git add for the file. + diff --git a/.cursor/rules/styling_rules.mdc b/.cursor/rules/styling_rules.mdc index e25e479..46c86f5 100644 --- a/.cursor/rules/styling_rules.mdc +++ b/.cursor/rules/styling_rules.mdc @@ -1,6 +1,13 @@ +--- +description: +globs: +alwaysApply: false +--- # Cursor Rule File – Tailwind, Shadcn, DaisyUI - Tailwind classes **only inside ui-kit**; no classes in consuming apps. +- Always use shadcn ui components with the shadcn CLI (npx shadcn@latest ) +- Initialitze - Never override Shadcn component CSS directly; extend via wrapper props. - Colours/spacings via CSS vars mapped to DaisyUI tokens. - Use `@apply` sparingly inside `theme.css`, never in JSX. diff --git a/components.json b/components.json new file mode 100644 index 0000000..3154a3d --- /dev/null +++ b/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/styles/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} diff --git a/docs/task-planning/task-2.1.md b/docs/task-planning/task-2.1.md new file mode 100644 index 0000000..1ea4a52 --- /dev/null +++ b/docs/task-planning/task-2.1.md @@ -0,0 +1,22 @@ +# Task 2.1 Planning - Form Primitives + +## Overview + +Task 2.1 involves completing the implementation of core form components (NumberInput, Select, Checkbox, RadioGroup) which already have base implementations but require tests and integration into a form story. + +## Tasks + +| Task Description | DoD (Definition of Done) | Status | +| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | -------- | +| Create unit tests for NumberInput component | Tests verify component renders correctly with all prop variations (label, description, error states, etc.) | Complete | +| Create unit tests for Select component | Tests verify component renders correctly with all prop variations and options are displayed correctly | Complete | +| Create unit tests for Checkbox component | Tests verify component renders correctly with all prop variations and state changes work | Complete | +| Create unit tests for RadioGroup component | Tests verify component renders correctly with all prop variations and option selection works | Complete | +| Set up a11y tests for all form components | All components pass accessibility tests with no violations | Complete | +| Create a form story displaying all components | Story shows all components with their variants in Storybook | Complete | + +## Implementation Notes + +- Unit tests will follow the pattern established in the existing TextInput and Button tests +- a11y tests will use the Storybook addon-a11y +- The form story will showcase all components with their various states (default, disabled, with error, etc.) diff --git a/docs/task-planning/task-2.1a-shadcn-upgrade.md b/docs/task-planning/task-2.1a-shadcn-upgrade.md new file mode 100644 index 0000000..29273ad --- /dev/null +++ b/docs/task-planning/task-2.1a-shadcn-upgrade.md @@ -0,0 +1,41 @@ +# Task 2.1a Planning: Shadcn UI Component Upgrade + +## Overview + +This task involves upgrading the current form components to use the Shadcn CLI for better alignment with the latest Shadcn UI implementations. This will ensure the components are easier to maintain and update in the future. + +## Task Breakdown + +| Task Description | Definition of Done (DoD) | Status | +| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +| Set up Shadcn CLI and configuration | components.json file created with proper configuration; CLI commands functioning correctly | complete | +| Reorganize project structure to match Shadcn standards | Directory structure and imports aligned with Shadcn expectations; Utils in correct location | complete | +| Update existing components using Shadcn CLI | All components (Button, Input, Select, Checkbox, RadioGroup) updated using the Shadcn CLI; Components maintain existing functionality | complete | +| Ensure wrapper components align with updated base components | All wrapper components (NumberInput, Select, Checkbox, RadioGroup) function correctly with the updated base components; No regressions in functionality | complete | + +## Implementation Strategy + +### Step 1: Project Structure Reorganization (Completed) + +- Create `src/lib` directory for utilities to match Shadcn standards +- Move `cn` utility from `src/utils/cn.ts` to `src/lib/utils.ts` +- Update imports across the project to use the new paths +- Update components.json to reflect the correct paths + +### Step 2: Component Updates (Completed) + +- Use the Shadcn CLI to update/reinstall all base components +- Ensure the updated components use the latest patterns and styles +- Verify all dependencies are correctly installed + +### Step 3: Wrapper Component Alignment (Completed) + +- Update wrapper components to work with the new base components +- Ensure all functionality is maintained +- Run tests to verify no regressions + +## Timeline + +- Estimated completion: 1-2 days (Completed in 1 day) +- First step: Setup and initial component upgrades (Completed) +- Second step: Complete remaining component updates and testing (Completed) diff --git a/package.json b/package.json index 00bb254..4c1a771 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@changesets/cli": "^2.29.4", "@commitlint/cli": "^19.8.1", "@commitlint/config-conventional": "^19.8.1", + "@eslint/js": "^9.27.0", "@storybook/addon-a11y": "8.6.14", "@storybook/addon-docs": "8.6.14", "@storybook/builder-vite": "8.6.14", @@ -34,7 +35,6 @@ "eslint": "^9.27.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", - "@eslint/js": "^9.27.0", "husky": "^8.0.0", "lint-staged": "^16.0.0", "postcss": "^8.4.35", @@ -46,6 +46,9 @@ "vitest": "^3.1.3" }, "dependencies": { + "@radix-ui/react-checkbox": "^1.3.1", + "@radix-ui/react-radio-group": "^1.3.6", + "@radix-ui/react-select": "^2.2.4", "react": "^19.1.0", "react-dom": "^19.1.0" }, diff --git a/packages/ui-kit/components.json b/packages/ui-kit/components.json new file mode 100644 index 0000000..3154a3d --- /dev/null +++ b/packages/ui-kit/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/styles/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} diff --git a/packages/ui-kit/package.json b/packages/ui-kit/package.json index 578dc18..ba06bab 100644 --- a/packages/ui-kit/package.json +++ b/packages/ui-kit/package.json @@ -21,7 +21,7 @@ "build": "tsc && vite build", "lint": "eslint .", "preview": "vite preview", - "test": "vitest", + "test": "vitest run", "test:coverage": "vitest run --coverage", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", @@ -34,14 +34,18 @@ "tokens-check": "node scripts/tokens-check.js" }, "dependencies": { - "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-checkbox": "^1.3.1", + "@radix-ui/react-radio-group": "^1.3.6", + "@radix-ui/react-select": "^2.2.4", + "@radix-ui/react-slot": "^1.2.2", "@types/testing-library__jest-dom": "^6.0.0", - "class-variance-authority": "^0.7.0", - "clsx": "^2.1.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "jsdom": "^26.1.0", + "lucide-react": "^0.511.0", "react": "^19.1.0", "react-dom": "^19.1.0", - "tailwind-merge": "^2.2.1", + "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7" }, "devDependencies": { diff --git a/packages/ui-kit/src/components/FormExample.stories.tsx b/packages/ui-kit/src/components/FormExample.stories.tsx new file mode 100644 index 0000000..521dbe9 --- /dev/null +++ b/packages/ui-kit/src/components/FormExample.stories.tsx @@ -0,0 +1,115 @@ +import React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Button } from './primitives/Button'; +import { TextInput } from './primitives/TextInput'; +import { NumberInput } from './primitives/NumberInput'; +import { Select } from './primitives/Select'; +import { Checkbox } from './primitives/Checkbox'; +import { RadioGroup } from './primitives/RadioGroup'; + +const colorOptions = [ + { value: 'red', label: 'Red' }, + { value: 'green', label: 'Green' }, + { value: 'blue', label: 'Blue' }, + { value: 'yellow', label: 'Yellow', disabled: true }, +]; + +const contactOptions = [ + { value: 'email', label: 'Email' }, + { value: 'phone', label: 'Phone' }, + { value: 'post', label: 'Post' }, +]; + +const FormExample = () => { + const [formState, setFormState] = React.useState({ + firstName: '', + age: '', + color: '', + contactMethod: '', + newsletter: false, + }); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + alert(JSON.stringify(formState, null, 2)); + }; + + const handleChange = (field: string, value: string | boolean) => { + setFormState((prev) => ({ ...prev, [field]: value })); + }; + + return ( +
+
+ ) => handleChange('firstName', e.target.value)} + /> + + ) => handleChange('age', e.target.value)} + description="Must be between 0 and 120" + /> + + ); + expect(screen.getByText('Favorite Color')).toBeInTheDocument(); + }); + + it('shows placeholder', () => { + render(); + expect(screen.getByText('Please select a value')).toBeInTheDocument(); + }); + + it('shows description text', () => { + render( - ); - } -); -Input.displayName = "Input"; +const Input = React.forwardRef>( + ({ className, type, ...props }, ref) => { + return ( + + ) + } +) +Input.displayName = "Input" -export { Input }; \ No newline at end of file +export { Input } diff --git a/packages/ui-kit/src/components/ui/radio-group.tsx b/packages/ui-kit/src/components/ui/radio-group.tsx index c7786a0..56f96f0 100644 --- a/packages/ui-kit/src/components/ui/radio-group.tsx +++ b/packages/ui-kit/src/components/ui/radio-group.tsx @@ -1,8 +1,8 @@ -"use client" - import * as React from "react" import * as RadioGroupPrimitive from "@radix-ui/react-radio-group" -import { cn } from "@/utils/cn" +import { Circle } from "lucide-react" + +import { cn } from "@/lib/utils" const RadioGroup = React.forwardRef< React.ElementRef, @@ -26,17 +26,17 @@ const RadioGroupItem = React.forwardRef< -
+ ) }) RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName -export { RadioGroup, RadioGroupItem } \ No newline at end of file +export { RadioGroup, RadioGroupItem } diff --git a/packages/ui-kit/src/components/ui/select.tsx b/packages/ui-kit/src/components/ui/select.tsx index 0823d39..2002f34 100644 --- a/packages/ui-kit/src/components/ui/select.tsx +++ b/packages/ui-kit/src/components/ui/select.tsx @@ -1,8 +1,8 @@ -"use client" - import * as React from "react" import * as SelectPrimitive from "@radix-ui/react-select" -import { cn } from "@/utils/cn" +import { Check, ChevronDown, ChevronUp } from "lucide-react" + +import { cn } from "@/lib/utils" const Select = SelectPrimitive.Root @@ -17,32 +17,54 @@ const SelectTrigger = React.forwardRef< span]:line-clamp-1", className )} {...props} > {children} - - - + )) SelectTrigger.displayName = SelectPrimitive.Trigger.displayName +const SelectScrollUpButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName + +const SelectScrollDownButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollDownButton.displayName = + SelectPrimitive.ScrollDownButton.displayName + const SelectContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef @@ -51,7 +73,7 @@ const SelectContent = React.forwardRef< + {children} + )) @@ -79,7 +103,7 @@ const SelectLabel = React.forwardRef< >(({ className, ...props }, ref) => ( )) @@ -92,30 +116,16 @@ const SelectItem = React.forwardRef< - + - - - + - {children} )) @@ -142,4 +152,6 @@ export { SelectLabel, SelectItem, SelectSeparator, -} \ No newline at end of file + SelectScrollUpButton, + SelectScrollDownButton, +} diff --git a/packages/ui-kit/src/lib/utils.ts b/packages/ui-kit/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/packages/ui-kit/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/packages/ui-kit/src/styles/globals.css b/packages/ui-kit/src/styles/globals.css index 58b7cf4..d9cd673 100644 --- a/packages/ui-kit/src/styles/globals.css +++ b/packages/ui-kit/src/styles/globals.css @@ -3,4 +3,69 @@ @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 0 0% 3.9%; + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 0 0% 3.9%; + --primary: 0 0% 9%; + --primary-foreground: 0 0% 98%; + --secondary: 0 0% 96.1%; + --secondary-foreground: 0 0% 9%; + --muted: 0 0% 96.1%; + --muted-foreground: 0 0% 45.1%; + --accent: 0 0% 96.1%; + --accent-foreground: 0 0% 9%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 89.8%; + --input: 0 0% 89.8%; + --ring: 0 0% 3.9%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --radius: 0.5rem + } + .dark { + --background: 0 0% 3.9%; + --foreground: 0 0% 98%; + --card: 0 0% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 0 0% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 0 0% 9%; + --secondary: 0 0% 14.9%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; + --input: 0 0% 14.9%; + --ring: 0 0% 83.1%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55% + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} \ No newline at end of file diff --git a/packages/ui-kit/tailwind.config.js b/packages/ui-kit/tailwind.config.js index 6e5c03f..f534e99 100644 --- a/packages/ui-kit/tailwind.config.js +++ b/packages/ui-kit/tailwind.config.js @@ -4,66 +4,77 @@ export default { './src/**/*.{js,ts,jsx,tsx}', './.storybook/**/*.{js,ts,jsx,tsx}', ], - darkMode: 'class', + darkMode: ['class', 'class'], theme: { - extend: { - colors: { - border: 'hsl(var(--border))', - input: 'hsl(var(--input))', - ring: 'hsl(var(--ring))', - background: 'hsl(var(--background))', - foreground: 'hsl(var(--foreground))', - primary: { - DEFAULT: 'hsl(var(--primary))', - foreground: 'hsl(var(--primary-foreground))', - }, - secondary: { - DEFAULT: 'hsl(var(--secondary))', - foreground: 'hsl(var(--secondary-foreground))', - }, - accent: { - DEFAULT: 'hsl(var(--accent))', - foreground: 'hsl(var(--accent-foreground))', - }, - destructive: { - DEFAULT: 'hsl(var(--destructive))', - foreground: 'hsl(var(--destructive-foreground))', - }, - card: { - DEFAULT: 'hsl(var(--card))', - foreground: 'hsl(var(--card-foreground))', - }, - popover: { - DEFAULT: 'hsl(var(--popover))', - foreground: 'hsl(var(--popover-foreground))', - }, - success: { - DEFAULT: 'hsl(var(--success))', - foreground: 'hsl(var(--success-foreground))', - }, - warning: { - DEFAULT: 'hsl(var(--warning))', - foreground: 'hsl(var(--warning-foreground))', - }, - info: { - DEFAULT: 'hsl(var(--info))', - foreground: 'hsl(var(--info-foreground))', - }, - }, - borderRadius: { - lg: 'var(--radius)', - md: 'calc(var(--radius) - 2px)', - sm: 'calc(var(--radius) - 4px)', - }, - boxShadow: { - sm: 'var(--shadow-sm)', - DEFAULT: 'var(--shadow)', - md: 'var(--shadow-md)', - lg: 'var(--shadow-lg)', - }, - }, + extend: { + colors: { + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))' + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))' + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))' + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))' + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))' + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))' + }, + success: { + DEFAULT: 'hsl(var(--success))', + foreground: 'hsl(var(--success-foreground))' + }, + warning: { + DEFAULT: 'hsl(var(--warning))', + foreground: 'hsl(var(--warning-foreground))' + }, + info: { + DEFAULT: 'hsl(var(--info))', + foreground: 'hsl(var(--info-foreground))' + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))' + }, + chart: { + '1': 'hsl(var(--chart-1))', + '2': 'hsl(var(--chart-2))', + '3': 'hsl(var(--chart-3))', + '4': 'hsl(var(--chart-4))', + '5': 'hsl(var(--chart-5))' + } + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)' + }, + boxShadow: { + sm: 'var(--shadow-sm)', + DEFAULT: 'var(--shadow)', + md: 'var(--shadow-md)', + lg: 'var(--shadow-lg)' + } + } }, - plugins: [require('daisyui')], + plugins: [require('daisyui'), require("tailwindcss-animate")], daisyui: { themes: ['light', 'dark'], base: true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9ee428c..0c055b9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,15 @@ importers: .: dependencies: + '@radix-ui/react-checkbox': + specifier: ^1.3.1 + version: 1.3.1(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-radio-group': + specifier: ^1.3.6 + version: 1.3.6(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-select': + specifier: ^2.2.4 + version: 2.2.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: specifier: ^19.1.0 version: 19.1.0 @@ -108,21 +117,33 @@ importers: packages/ui-kit: dependencies: + '@radix-ui/react-checkbox': + specifier: ^1.3.1 + version: 1.3.1(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-radio-group': + specifier: ^1.3.6 + version: 1.3.6(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-select': + specifier: ^2.2.4 + version: 2.2.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': - specifier: ^1.0.2 + specifier: ^1.2.2 version: 1.2.2(@types/react@19.1.4)(react@19.1.0) '@types/testing-library__jest-dom': specifier: ^6.0.0 version: 6.0.0 class-variance-authority: - specifier: ^0.7.0 + specifier: ^0.7.1 version: 0.7.1 clsx: - specifier: ^2.1.0 + specifier: ^2.1.1 version: 2.1.1 jsdom: specifier: ^26.1.0 version: 26.1.0 + lucide-react: + specifier: ^0.511.0 + version: 0.511.0(react@19.1.0) react: specifier: ^19.1.0 version: 19.1.0 @@ -130,7 +151,7 @@ importers: specifier: ^19.1.0 version: 19.1.0(react@19.1.0) tailwind-merge: - specifier: ^2.2.1 + specifier: ^2.6.0 version: 2.6.0 tailwindcss-animate: specifier: ^1.0.7 @@ -1307,6 +1328,21 @@ packages: resolution: {integrity: sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@floating-ui/core@1.7.0': + resolution: {integrity: sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==} + + '@floating-ui/dom@1.7.0': + resolution: {integrity: sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==} + + '@floating-ui/react-dom@2.1.2': + resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.9': + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -1407,6 +1443,51 @@ packages: engines: {node: '>=18'} hasBin: true + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.2': + resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==} + + '@radix-ui/react-arrow@1.1.6': + resolution: {integrity: sha512-2JMfHJf/eVnwq+2dewT3C0acmCWD3XiVA1Da+jTDqo342UlU13WvXtqHhG+yJw5JeQmu4ue2eMy6gcEArLBlcw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-checkbox@1.3.1': + resolution: {integrity: sha512-xTaLKAO+XXMPK/BpVTSaAAhlefmvMSACjIhK9mGsImvX2ljcTDm8VGR1CuS1uYcNdR5J+oiOhoJZc5un6bh3VQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.6': + resolution: {integrity: sha512-PbhRFK4lIEw9ADonj48tiYWzkllz81TM7KVYyyMMw2cwHO7D5h4XKEblL8NlaRisTK3QTe6tBEhDccFUryxHBQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-compose-refs@1.1.2': resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} peerDependencies: @@ -1416,6 +1497,159 @@ packages: '@types/react': optional: true + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.9': + resolution: {integrity: sha512-way197PiTvNp+WBP7svMJasHl+vibhWGQDb6Mgf5mhEWJkgb85z7Lfl9TUdkqpWsf8GRNmoopx9ZxCyDzmgRMQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.2': + resolution: {integrity: sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.6': + resolution: {integrity: sha512-r9zpYNUQY+2jWHWZGyddQLL9YHkM/XvSFHVcWs7bdVuxMAnCwTAuy6Pf47Z4nw7dYcUou1vg/VgjjrrH03VeBw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-popper@1.2.6': + resolution: {integrity: sha512-7iqXaOWIjDBfIG7aq8CUEeCSsQMLFdn7VEE8TaFz704DtEzpPHR7w/uuzRflvKgltqSAImgcmxQ7fFX3X7wasg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.8': + resolution: {integrity: sha512-hQsTUIn7p7fxCPvao/q6wpbxmCwgLrlz+nOrJgC+RwfZqWY/WN+UMqkXzrtKbPrF82P43eCTl3ekeKuyAQbFeg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.4': + resolution: {integrity: sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.2': + resolution: {integrity: sha512-uHa+l/lKfxuDD2zjN/0peM/RhhSmRjr5YWdk/37EnSv1nJ88uvG85DPexSm8HdFQROd2VdERJ6ynXbkCFi+APw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-radio-group@1.3.6': + resolution: {integrity: sha512-1tfTAqnYZNVwSpFhCT273nzK8qGBReeYnNTPspCggqk1fvIrfVxJekIuBFidNivzpdiMqDwVGnQvHqXrRPM4Og==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.9': + resolution: {integrity: sha512-ZzrIFnMYHHCNqSNCsuN6l7wlewBEq0O0BCSBkabJMFXVO51LRUTq71gLP1UxFvmrXElqmPjA5VX7IqC9VpazAQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.2.4': + resolution: {integrity: sha512-/OOm58Gil4Ev5zT8LyVzqfBcij4dTHYdeyuF5lMHZ2bIp0Lk9oETocYiJ5QC0dHekEQnK6L/FNJCceeb4AkZ6Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-slot@1.2.2': resolution: {integrity: sha512-y7TBO4xN4Y94FvcWIOIh18fM4R1A8S4q1jhoz4PNzOoHsFcN8pogcFmZrTYAm4F9VRUrWP/Mw7xSKybIeRI+CQ==} peerDependencies: @@ -1425,6 +1659,94 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.2': + resolution: {integrity: sha512-ORCmRUbNiZIv6uV5mhFrhsIKw4UX/N3syZtyqvry61tbGm4JlgQuSn0hk5TwCARsCjkcnuRkSdCE3xfb+ADHew==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@rollup/pluginutils@5.1.4': resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} engines: {node: '>=14.0.0'} @@ -2062,6 +2384,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} @@ -2601,6 +2927,9 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} @@ -3026,6 +3355,10 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -3686,6 +4019,11 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@0.511.0: + resolution: {integrity: sha512-VK5a2ydJ7xm8GvBeKLS9mu1pVK6ucef9780JVUjw6bAjJL/QXnd4Y0p7SPeOUMC27YhzNCZvm5d/QX0Tp3rc0w==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -4239,6 +4577,36 @@ packages: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.0: + resolution: {integrity: sha512-sGsQtcjMqdQyijAHytfGEELB8FufGbfXIsvUTe+NLx1GDRJCXtCFLBLUI1eyZCKXXvbEU2C6gai0PZKoIE9Vbg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react@19.1.0: resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} engines: {node: '>=0.10.0'} @@ -4856,6 +5224,26 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + utf8-byte-length@1.0.5: resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} @@ -6341,6 +6729,23 @@ snapshots: '@eslint/core': 0.14.0 levn: 0.4.1 + '@floating-ui/core@1.7.0': + dependencies: + '@floating-ui/utils': 0.2.9 + + '@floating-ui/dom@1.7.0': + dependencies: + '@floating-ui/core': 1.7.0 + '@floating-ui/utils': 0.2.9 + + '@floating-ui/react-dom@2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@floating-ui/dom': 1.7.0 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@floating-ui/utils@0.2.9': {} + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.6': @@ -6449,12 +6854,213 @@ snapshots: dependencies: playwright: 1.52.0 + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.2': {} + + '@radix-ui/react-arrow@1.1.6(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-checkbox@1.3.1(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-collection@1.1.6(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.2.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.4)(react@19.1.0)': dependencies: react: 19.1.0 optionalDependencies: '@types/react': 19.1.4 + '@radix-ui/react-context@1.1.2(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-direction@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-dismissable-layer@1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-focus-guards@1.1.2(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-focus-scope@1.1.6(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-id@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-popper@1.2.6(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@floating-ui/react-dom': 2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-arrow': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/rect': 1.1.1 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-portal@1.1.8(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-presence@1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-primitive@2.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-slot': 1.2.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-radio-group@1.3.6(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-roving-focus@1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/react-select@2.2.4(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + aria-hidden: 1.2.6 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-remove-scroll: 2.7.0(@types/react@19.1.4)(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + '@radix-ui/react-slot@1.2.2(@types/react@19.1.4)(react@19.1.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.4)(react@19.1.0) @@ -6462,6 +7068,71 @@ snapshots: optionalDependencies: '@types/react': 19.1.4 + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.4)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-previous@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.1.4)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.4)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.4 + + '@radix-ui/react-visually-hidden@1.2.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + '@types/react-dom': 19.1.5(@types/react@19.1.4) + + '@radix-ui/rect@1.1.1': {} + '@rollup/pluginutils@5.1.4(rollup@4.41.0)': dependencies: '@types/estree': 1.0.7 @@ -7242,6 +7913,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + aria-query@5.3.0: dependencies: dequal: 2.0.3 @@ -7828,6 +8503,8 @@ snapshots: detect-indent@6.1.0: {} + detect-node-es@1.1.0: {} + didyoumean@1.2.2: {} diff-sequences@29.6.3: {} @@ -8409,6 +9086,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -9112,6 +9791,10 @@ snapshots: dependencies: yallist: 3.1.1 + lucide-react@0.511.0(react@19.1.0): + dependencies: + react: 19.1.0 + lz-string@1.5.0: {} magic-string@0.27.0: @@ -9600,6 +10283,33 @@ snapshots: react-refresh@0.17.0: {} + react-remove-scroll-bar@2.3.8(@types/react@19.1.4)(react@19.1.0): + dependencies: + react: 19.1.0 + react-style-singleton: 2.2.3(@types/react@19.1.4)(react@19.1.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.4 + + react-remove-scroll@2.7.0(@types/react@19.1.4)(react@19.1.0): + dependencies: + react: 19.1.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.1.4)(react@19.1.0) + react-style-singleton: 2.2.3(@types/react@19.1.4)(react@19.1.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.1.4)(react@19.1.0) + use-sidecar: 1.1.3(@types/react@19.1.4)(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.4 + + react-style-singleton@2.2.3(@types/react@19.1.4)(react@19.1.0): + dependencies: + get-nonce: 1.0.1 + react: 19.1.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.4 + react@19.1.0: {} read-cache@1.0.0: @@ -10295,6 +11005,21 @@ snapshots: dependencies: punycode: 2.3.1 + use-callback-ref@1.3.3(@types/react@19.1.4)(react@19.1.0): + dependencies: + react: 19.1.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.4 + + use-sidecar@1.1.3(@types/react@19.1.4)(react@19.1.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.1.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.4 + utf8-byte-length@1.0.5: {} util-deprecate@1.0.2: {} diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..9175a85 --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} \ No newline at end of file From 4d1197116fa70cd1f26b4edbb93ac7c667e6c457 Mon Sep 17 00:00:00 2001 From: Christoph Mussenbrock Date: Tue, 20 May 2025 17:29:48 +0200 Subject: [PATCH 6/8] docs: mark task 2.1 as PR status --- docs/project_plan.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/project_plan.md b/docs/project_plan.md index 8e13a58..6790b0c 100644 --- a/docs/project_plan.md +++ b/docs/project_plan.md @@ -42,7 +42,7 @@ A pragmatic breakdown into **four one‑week sprints** plus a preparatory **Spri | # | Task | DoD | Status | | --- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ------ | -| 2.1 | Add NumberInput, Select, Checkbox, RadioGroup components. | Unit & a11y tests pass; form story displays all. | | +| 2.1 | Add NumberInput, Select, Checkbox, RadioGroup components. | Unit & a11y tests pass; form story displays all. | PR | | 2.2 | Integrate **React Hook Form + Zod**; create `FormGrid` + `FormGroup`. | Story "Form Example" submits & reports validation errors in Storybook interaction test. | | | 2.3 | Implement Zustand session store skeleton with dark‑mode flag. | Vitest verifies default state + setter actions. | | | 2.4 | ESLint rule enforcing named `useEffect` & cleanup. | Failing example in test repo triggers lint error; real code passes. | | From 020b9ee81ee668ef91f012bdd383ee57c6994628 Mon Sep 17 00:00:00 2001 From: Christoph Mussenbrock Date: Tue, 20 May 2025 17:46:31 +0200 Subject: [PATCH 7/8] fix: resolve TypeScript errors by defining interfaces in component files --- .cursor/rules/coding.mdc | 55 ++++++++++++------- .../components/primitives/Button/Button.tsx | 2 +- .../primitives/Checkbox/Checkbox.tsx | 12 +++- .../components/primitives/Checkbox/index.ts | 3 +- .../primitives/NumberInput/NumberInput.tsx | 22 ++++++-- .../primitives/NumberInput/index.ts | 3 +- .../primitives/RadioGroup/RadioGroup.tsx | 20 ++++++- .../components/primitives/RadioGroup/index.ts | 3 +- .../components/primitives/Select/Select.tsx | 22 +++++++- .../src/components/primitives/Select/index.ts | 3 +- 10 files changed, 106 insertions(+), 39 deletions(-) diff --git a/.cursor/rules/coding.mdc b/.cursor/rules/coding.mdc index 47b6f8c..d64aa75 100644 --- a/.cursor/rules/coding.mdc +++ b/.cursor/rules/coding.mdc @@ -12,25 +12,38 @@ alwaysApply: true - Before starting coding, always present a plan for approval. - Tasks are in docs/project_plan.md - Each task will be implemented via a feature branch and a PR to the develop branch. -- Always follow the following recipe for implementing tasks: - 1. Only start implementing a task after the user has explicitly told so. - 2. Before starting coding, create a task planning document (.md) in the docs/task-planning folder. - 3. The task planning document contains a table with three columns: tasks description, DoD (Definition of Done) and Status. Status is open, working, checking, review, complete. Initially all tasks are "open". - 1. Open = the task hasn't been worked on. - 2. Working = the task is currently being implemented. - 3. Checking = the DoD of the tasks are being checked. - 4. Review = the user is reviewing the result. - 5. complete = the user has approved the result and the task is complete. - 4. After creating the task planning document, let the user review the doc. - 5. After the user has approved the task planning document, implement each task one after the other. - 6. After implementing a task, check the criteria for DoD and report the result to the user. - 7. If DoD is not met, fix the problem until DoD is met. - 8. Before and after each task, update each task in the table with the right status. - 9. After finishing implementing, perform all necessary tests and check if the DoD for this task is met. - 10. Report on test results and DoD criteria and ask user if a PR should be submitted. - 11. If the user approves submitting a PR, and before PR is submitted, the task is marked with "PR" in docs/project_plan.md. - 12. After PR ist submitted, report to the user and wait for manual instructions. - 13. The user will then review and merge the PR or ask for updates. - 14. Pull the repo again to check if the PR has been merged. - 15. After task is completed (PR merged), the task is marked with a checkmark in docs/project_plan.md. This change does not warrant a separate PR, it will be included in the next PR. Just do git add for the file. + +# Recipe for implementing tasks +Always follow the following recipe for implementing tasks: +1. Only start implementing a task after the user has explicitly told so. +2. Before starting coding, create a task planning document (.md) in the docs/task-planning folder. +3. The task planning document contains a table with three columns: tasks description, DoD (Definition of Done) and Status. Status is open, working, checking, review, complete. Initially all tasks are "open". + 1. Open = the task hasn't been worked on. + 2. Working = the task is currently being implemented. + 3. Checking = the DoD of the tasks are being checked. + 4. Review = the user is reviewing the result. + 5. complete = the user has approved the result and the task is complete. +4. After creating the task planning document, let the user review the doc. +5. After the user has approved the task planning document, implement each task one after the other. +6. After implementing a task, check the criteria for DoD and report the result to the user. +7. If DoD is not met, fix the problem until DoD is met. +8. Before and after each task, update each task in the table with the right status. +9. After finishing implementing, perform all necessary tests and check if the DoD for this task is met. +10. Report on test results and DoD criteria and ask user if a PR should be submitted. +11. If the user approves submitting a PR, and before PR is submitted, the task is marked with "PR" in docs/project_plan.md. +12. After PR ist submitted, report to the user and wait for manual instructions. +13. The user will then review and merge the PR or ask for updates. +14. Pull the repo again to check if the PR has been merged. +15. After task is completed (PR merged), the task is marked with a checkmark in docs/project_plan.md. This change does not warrant a separate PR, it will be included in the next PR. Just do git add for the file. +# Instructions to handle error situations: +- CI Pipeline fails: + 1. List the last github actions and find out which actions failed. + 2. Fetch the git actions log with `gh run view --log | cat` + 3. Analyze the log and make a proposal how to fix it. + 4. Let the user review / update the proposal, then execute the reviewed/updated proposal. +- Linter errors: + 1. Run `pnpm run lint` + 2. Find the linter errors + 3. Fix + \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/Button/Button.tsx b/packages/ui-kit/src/components/primitives/Button/Button.tsx index e7c328c..8dbc962 100644 --- a/packages/ui-kit/src/components/primitives/Button/Button.tsx +++ b/packages/ui-kit/src/components/primitives/Button/Button.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Button as ShadcnButton, type ButtonProps as ShadcnButtonProps } from '@/components/ui/button'; -import { cn } from '@/utils/cn'; +import { cn } from '@/lib/utils'; import type { ButtonProps } from './types'; export const Button = React.forwardRef( diff --git a/packages/ui-kit/src/components/primitives/Checkbox/Checkbox.tsx b/packages/ui-kit/src/components/primitives/Checkbox/Checkbox.tsx index af8ca59..fdc1aca 100644 --- a/packages/ui-kit/src/components/primitives/Checkbox/Checkbox.tsx +++ b/packages/ui-kit/src/components/primitives/Checkbox/Checkbox.tsx @@ -1,7 +1,17 @@ import * as React from 'react'; import { cn } from '@/lib/utils'; import { Checkbox as ShadcnCheckbox } from '@/components/ui/checkbox'; -import { CheckboxProps } from './types'; + +export interface CheckboxProps extends React.ComponentPropsWithoutRef { + /** Label text displayed next to the checkbox */ + label?: string; + /** Description/help text rendered below */ + description?: string; + /** Marks input as invalid */ + error?: string; + /** CSS class name */ + className?: string; +} export const Checkbox = React.forwardRef( ( diff --git a/packages/ui-kit/src/components/primitives/Checkbox/index.ts b/packages/ui-kit/src/components/primitives/Checkbox/index.ts index f601b0e..7c39dc8 100644 --- a/packages/ui-kit/src/components/primitives/Checkbox/index.ts +++ b/packages/ui-kit/src/components/primitives/Checkbox/index.ts @@ -1,2 +1 @@ -export * from './Checkbox'; -export * from './types'; \ No newline at end of file +export * from './Checkbox'; \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/NumberInput/NumberInput.tsx b/packages/ui-kit/src/components/primitives/NumberInput/NumberInput.tsx index 3464e97..3184b99 100644 --- a/packages/ui-kit/src/components/primitives/NumberInput/NumberInput.tsx +++ b/packages/ui-kit/src/components/primitives/NumberInput/NumberInput.tsx @@ -1,7 +1,20 @@ import * as React from 'react'; import { Input } from '@/components/ui/input'; -import { cn } from '@/lib/utils'; -import { NumberInputProps } from './types'; + +export interface NumberInputProps extends React.ComponentPropsWithoutRef { + /** Label text displayed above the input */ + label?: string; + /** Description/help text rendered below */ + description?: string; + /** Marks input as invalid */ + error?: string; + /** Minimum value allowed */ + min?: number; + /** Maximum value allowed */ + max?: number; + /** Step value for incrementing/decrementing */ + step?: number; +} export const NumberInput = React.forwardRef( ( @@ -22,11 +35,8 @@ export const NumberInput = React.forwardRef( max={max} step={step} aria-invalid={!!error} + className={error ? 'border-destructive text-destructive-foreground' : ''} {...props} - className={cn( - error ? 'border-destructive text-destructive-foreground' : '', - props.className - )} /> {description && !error && (

{description}

diff --git a/packages/ui-kit/src/components/primitives/NumberInput/index.ts b/packages/ui-kit/src/components/primitives/NumberInput/index.ts index da0aed6..0e3b691 100644 --- a/packages/ui-kit/src/components/primitives/NumberInput/index.ts +++ b/packages/ui-kit/src/components/primitives/NumberInput/index.ts @@ -1,2 +1 @@ -export * from './NumberInput'; -export * from './types'; \ No newline at end of file +export * from './NumberInput'; \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/RadioGroup/RadioGroup.tsx b/packages/ui-kit/src/components/primitives/RadioGroup/RadioGroup.tsx index 05329a0..df578df 100644 --- a/packages/ui-kit/src/components/primitives/RadioGroup/RadioGroup.tsx +++ b/packages/ui-kit/src/components/primitives/RadioGroup/RadioGroup.tsx @@ -1,7 +1,25 @@ import * as React from 'react'; import { cn } from '@/lib/utils'; import { RadioGroup as ShadcnRadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; -import { RadioGroupProps } from './types'; + +export interface RadioOption { + value: string; + label: string; + disabled?: boolean; +} + +export interface RadioGroupProps extends Omit, 'children'> { + /** Label text displayed above the radio group */ + label?: string; + /** Description/help text rendered below */ + description?: string; + /** Marks input as invalid */ + error?: string; + /** Options for the radio group */ + options: RadioOption[]; + /** CSS class name */ + className?: string; +} export const RadioGroup = React.forwardRef( ( diff --git a/packages/ui-kit/src/components/primitives/RadioGroup/index.ts b/packages/ui-kit/src/components/primitives/RadioGroup/index.ts index aaf3826..3e3ca7e 100644 --- a/packages/ui-kit/src/components/primitives/RadioGroup/index.ts +++ b/packages/ui-kit/src/components/primitives/RadioGroup/index.ts @@ -1,2 +1 @@ -export * from './RadioGroup'; -export * from './types'; \ No newline at end of file +export * from './RadioGroup'; \ No newline at end of file diff --git a/packages/ui-kit/src/components/primitives/Select/Select.tsx b/packages/ui-kit/src/components/primitives/Select/Select.tsx index 4f88b2e..c4450ff 100644 --- a/packages/ui-kit/src/components/primitives/Select/Select.tsx +++ b/packages/ui-kit/src/components/primitives/Select/Select.tsx @@ -7,7 +7,27 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select'; -import { SelectProps } from './types'; + +export interface SelectOption { + value: string; + label: string; + disabled?: boolean; +} + +export interface SelectProps extends Omit, 'children'> { + /** Label text displayed above the select */ + label?: string; + /** Description/help text rendered below */ + description?: string; + /** Marks select as invalid */ + error?: string; + /** Placeholder text */ + placeholder?: string; + /** Options to display in the dropdown */ + options: SelectOption[]; + /** CSS class name */ + className?: string; +} export const Select = React.forwardRef( ( diff --git a/packages/ui-kit/src/components/primitives/Select/index.ts b/packages/ui-kit/src/components/primitives/Select/index.ts index 8abb30b..e4f6f2b 100644 --- a/packages/ui-kit/src/components/primitives/Select/index.ts +++ b/packages/ui-kit/src/components/primitives/Select/index.ts @@ -1,2 +1 @@ -export * from './Select'; -export * from './types'; \ No newline at end of file +export * from './Select'; \ No newline at end of file From c15005244b2015ac4e2467920b073b874d1c1622 Mon Sep 17 00:00:00 2001 From: Christoph Mussenbrock Date: Tue, 20 May 2025 17:52:58 +0200 Subject: [PATCH 8/8] fix: move TextInput types into component and properly handle size prop --- .../primitives/TextInput/TextInput.tsx | 39 +++++++++++++++++-- .../components/primitives/TextInput/types.ts | 14 ------- 2 files changed, 35 insertions(+), 18 deletions(-) delete mode 100644 packages/ui-kit/src/components/primitives/TextInput/types.ts diff --git a/packages/ui-kit/src/components/primitives/TextInput/TextInput.tsx b/packages/ui-kit/src/components/primitives/TextInput/TextInput.tsx index fc72432..e1bdc5f 100644 --- a/packages/ui-kit/src/components/primitives/TextInput/TextInput.tsx +++ b/packages/ui-kit/src/components/primitives/TextInput/TextInput.tsx @@ -1,13 +1,43 @@ import * as React from 'react'; import { Input } from '@/components/ui/input'; import { cn } from '@/lib/utils'; -import { TextInputProps } from './types'; + +export interface TextInputProps extends Omit, 'size'> { + /** Label text displayed above the input */ + label?: string; + /** Description/help text rendered below */ + description?: string; + /** Marks input as invalid */ + error?: string; + /** Visual size of the input */ + size?: 'default' | 'sm' | 'lg'; + /** Optional CSS class name for the wrapper div */ + className?: string; + /** Optional CSS class name for the input element */ + inputClassName?: string; +} export const TextInput = React.forwardRef( ( - { label, description, error, className, ...props }, + { + label, + description, + error, + size = 'default', + className, + inputClassName, + ...props + }, ref ) => { + // Size classes for the input element + let sizeClass = ''; + if (size === 'sm') { + sizeClass = 'h-8 text-xs'; + } else if (size === 'lg') { + sizeClass = 'h-10 text-base'; + } + return (
{label && ( @@ -18,11 +48,12 @@ export const TextInput = React.forwardRef( {description && !error && (

{description}

diff --git a/packages/ui-kit/src/components/primitives/TextInput/types.ts b/packages/ui-kit/src/components/primitives/TextInput/types.ts deleted file mode 100644 index c4dc3e5..0000000 --- a/packages/ui-kit/src/components/primitives/TextInput/types.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Input } from '@/components/ui/input'; - -export interface TextInputProps extends Omit, 'size'> { - /** Label text displayed above the input */ - label?: string; - /** Description/help text rendered below */ - description?: string; - /** Marks input as invalid */ - error?: string; - /** Visual size of the input */ - size?: 'default' | 'sm' | 'lg'; - /** Optional CSS class name */ - className?: string; -} \ No newline at end of file