diff --git a/frontend/package.json b/frontend/package.json index 449f9c7..786414f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,11 +15,17 @@ "@types/react-dom": "^19.0.0", "@types/react-router-dom": "^5.3.3", "@vitejs/plugin-react": "^4.3.3", + "@types/jest": "30.0.0", + "@testing-library/react": "10.4.1", + "@testing-library/jest-dom": "6.9.1", + "@testing-library/user-event": "14.6.1", + "@storybook/react": "10.0.1", "typescript": "^5.7.3", "vite": "^6.0.7", "esbuild": "^0.21.0", "terser": "5.44.0", - "babel-plugin-transform-remove-console": "6.9.4" + "babel-plugin-transform-remove-console": "6.9.4", + "framer-motion": "12.23.24" }, "scripts": { "dev": "vite", diff --git a/frontend/src/components/StepSetup/StepSetup.stories.tsx b/frontend/src/components/StepSetup/StepSetup.stories.tsx new file mode 100644 index 0000000..5d29c2d --- /dev/null +++ b/frontend/src/components/StepSetup/StepSetup.stories.tsx @@ -0,0 +1,79 @@ +import React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import StepSetup from './StepSetup'; + +const meta: Meta = { + title: 'Components/StepSetup', + component: StepSetup, + parameters: { + layout: 'padded', + }, + tags: ['autodocs'], +}; + +export default meta; +type Story = StoryObj; + +const defaultSteps = [ + { id: 'step-1', title: 'Account Setup', subtitle: 'Create your account' }, + { id: 'step-2', title: 'Profile Information', subtitle: 'Add personal details' }, + { id: 'step-3', title: 'Preferences', subtitle: 'Customize your experience', optional: true }, + { id: 'step-4', title: 'Confirmation', subtitle: 'Review and confirm' }, +]; + +export const Horizontal: Story = { + args: { + steps: defaultSteps, + defaultCurrent: 1, + orientation: 'horizontal', + }, +}; + +export const Vertical: Story = { + args: { + steps: defaultSteps, + defaultCurrent: 1, + orientation: 'vertical', + }, + parameters: { + layout: 'padded', + }, +}; + +export const ClickableFalse: Story = { + args: { + steps: defaultSteps, + current: 2, + clickable: false, + }, + name: 'Non-Clickable Steps', +}; + +export const AnimatedFalse: Story = { + args: { + steps: defaultSteps, + defaultCurrent: 1, + animated: false, + }, + name: 'Without Animation', +}; + +export const DifferentSizes: Story = { + render: () => ( +
+
+

Small

+ +
+
+

Medium (default)

+ +
+
+

Large

+ +
+
+ ), + name: 'Different Sizes', +}; \ No newline at end of file diff --git a/frontend/src/components/StepSetup/StepSetup.test.tsx b/frontend/src/components/StepSetup/StepSetup.test.tsx new file mode 100644 index 0000000..9164e8e --- /dev/null +++ b/frontend/src/components/StepSetup/StepSetup.test.tsx @@ -0,0 +1,127 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import '@testing-library/jest-dom'; +import StepSetup from './StepSetup'; + +const mockSteps = [ + { id: 'step-1', title: 'First Step', subtitle: 'Description 1' }, + { id: 'step-2', title: 'Second Step' }, + { id: 'step-3', title: 'Third Step', subtitle: 'Description 3', optional: true }, +]; + +describe('StepSetup', () => { + // a) Test verschiedener Step-Counts + test('renders correct number of steps', () => { + render(); + + expect(screen.getByText('First Step')).toBeInTheDocument(); + expect(screen.getByText('Second Step')).toBeInTheDocument(); + expect(screen.getByText('Third Step')).toBeInTheDocument(); + }); + + test('renders empty state correctly', () => { + render(); + + expect(screen.getByText('No steps available')).toBeInTheDocument(); + }); + + // b) Keyboard-Navigation und Klicks + test('handles click navigation when clickable', async () => { + const user = userEvent.setup(); + const onChange = jest.fn(); + + render(); + + const secondStep = screen.getByRole('tab', { name: /second step/i }); + await user.click(secondStep); + + expect(onChange).toHaveBeenCalledWith(1); + }); + + test('handles keyboard navigation', async () => { + const user = userEvent.setup(); + const onChange = jest.fn(); + + render( + + ); + + const firstStep = screen.getByRole('tab', { name: /first step/i }); + firstStep.focus(); + + // Right arrow to next step + await user.keyboard('{ArrowRight}'); + expect(onChange).toHaveBeenCalledWith(1); + + // Home key to first step + await user.keyboard('{Home}'); + expect(onChange).toHaveBeenCalledWith(0); + + // End key to last step + await user.keyboard('{End}'); + expect(onChange).toHaveBeenCalledWith(2); + }); + + // c) ARIA-Attribute Tests + test('has correct ARIA attributes', () => { + render(); + + const tablist = screen.getByRole('tablist'); + expect(tablist).toBeInTheDocument(); + + const tabs = screen.getAllByRole('tab'); + expect(tabs).toHaveLength(3); + + // Second step should be selected + expect(tabs[1]).toHaveAttribute('aria-selected', 'true'); + expect(tabs[1]).toHaveAttribute('aria-current', 'step'); + }); + + // d) Controlled vs Uncontrolled Tests + test('works in controlled mode', () => { + const onChange = jest.fn(); + + const { rerender } = render( + + ); + + // Click should call onChange but not change internal state in controlled mode + const secondStep = screen.getByRole('tab', { name: /second step/i }); + fireEvent.click(secondStep); + + expect(onChange).toHaveBeenCalledWith(1); + // Current step should still be first (controlled by prop) + expect(screen.getByRole('tab', { name: /first step/i })) + .toHaveAttribute('aria-selected', 'true'); + + // Update prop should change current step + rerender(); + expect(screen.getByRole('tab', { name: /second step/i })) + .toHaveAttribute('aria-selected', 'true'); + }); + + test('works in uncontrolled mode', () => { + const onChange = jest.fn(); + + render(); + + const secondStep = screen.getByRole('tab', { name: /second step/i }); + fireEvent.click(secondStep); + + expect(onChange).toHaveBeenCalledWith(1); + expect(secondStep).toHaveAttribute('aria-selected', 'true'); + }); + + test('clamps out-of-range current values', () => { + render(); + + // Should clamp to last step + const lastStep = screen.getByRole('tab', { name: /third step/i }); + expect(lastStep).toHaveAttribute('aria-selected', 'true'); + }); +}); \ No newline at end of file diff --git a/frontend/src/components/StepSetup/StepSetup.tsx b/frontend/src/components/StepSetup/StepSetup.tsx new file mode 100644 index 0000000..a4d8879 --- /dev/null +++ b/frontend/src/components/StepSetup/StepSetup.tsx @@ -0,0 +1,516 @@ +import React, { + useState, + useEffect, + useId, + useCallback, + KeyboardEvent +} from 'react'; +import { motion, MotionConfig, SpringOptions } from 'framer-motion'; + +// ===== TYP-DEFINITIONEN ===== +export interface Step { + id: string; + title: string; + subtitle?: string; + optional?: boolean; +} + +export interface StepSetupProps { + /** Array der Schritte mit ID, Titel und optionalen Eigenschaften */ + steps: Step[]; + /** Kontrollierter aktueller Schritt-Index */ + current?: number; + /** Unkontrollierter Standard-Schritt-Index */ + defaultCurrent?: number; + /** Callback bei Schrittänderung */ + onChange?: (index: number) => void; + /** Ausrichtung des Steppers */ + orientation?: 'horizontal' | 'vertical'; + /** Ob Steps anklickbar sind */ + clickable?: boolean; + /** Größe der Step-Komponente */ + size?: 'sm' | 'md' | 'lg'; + /** Animation aktivieren/deaktivieren */ + animated?: boolean; + /** Zusätzliche CSS-Klassen */ + className?: string; +} + +export interface StepState { + currentStep: number; + isControlled: boolean; +} + +// ===== HOOK FÜR ZUSTANDSVERWALTUNG ===== +export const useStepSetup = (props: StepSetupProps) => { + const { + steps, + current, + defaultCurrent = 0, + onChange, + clickable = true + } = props; + + const [internalStep, setInternalStep] = useState(defaultCurrent); + const isControlled = current !== undefined; + + const currentStep = isControlled ? current : internalStep; + + // Clamp den Schritt-Index auf gültigen Bereich + const clampedStep = Math.max(0, Math.min(currentStep, steps.length - 1)); + + const setStep = useCallback((newStep: number) => { + const clampedNewStep = Math.max(0, Math.min(newStep, steps.length - 1)); + + if (!isControlled) { + setInternalStep(clampedNewStep); + } + + onChange?.(clampedNewStep); + }, [isControlled, onChange, steps.length]); + + const goToNext = useCallback(() => { + if (clampedStep < steps.length - 1) { + setStep(clampedStep + 1); + } + }, [clampedStep, steps.length, setStep]); + + const goToPrev = useCallback(() => { + if (clampedStep > 0) { + setStep(clampedStep - 1); + } + }, [clampedStep, setStep]); + + const goToStep = useCallback((index: number) => { + if (clickable) { + setStep(index); + } + }, [clickable, setStep]); + + // Warnung bei Duplicate IDs (nur in Development) + useEffect(() => { + if (process.env.NODE_ENV !== 'production') { + const stepIds = steps.map(step => step.id); + const duplicateIds = stepIds.filter((id, index) => stepIds.indexOf(id) !== index); + + if (duplicateIds.length > 0) { + console.warn( + `StepSetup: Duplicate step IDs found: ${duplicateIds.join(', ')}. ` + + `Step IDs should be unique.` + ); + } + } + }, [steps]); + + return { + currentStep: clampedStep, + setStep, + goToNext, + goToPrev, + goToStep, + isControlled + }; +}; + +// ===== ANIMATIONS-KONFIGURATION ===== +const getAnimationConfig = (animated: boolean): { reduced: { duration: number }; normal: SpringOptions } => ({ + reduced: { duration: 0 }, // Keine Animation + normal: { + stiffness: 500, + damping: 30, + mass: 0.5 + } +}); + +// ===== HILFSFUNKTIONEN ===== + +/** + * Berechnet die Step-Größenklassen basierend auf der size-Prop + */ +const getSizeClasses = (size: StepSetupProps['size'] = 'md') => { + const sizes = { + sm: { + step: 'w-8 h-8 text-sm', + icon: 'w-4 h-4', + title: 'text-sm', + subtitle: 'text-xs' + }, + md: { + step: 'w-10 h-10 text-base', + icon: 'w-5 h-5', + title: 'text-base', + subtitle: 'text-sm' + }, + lg: { + step: 'w-12 h-12 text-lg', + icon: 'w-6 h-6', + title: 'text-lg', + subtitle: 'text-base' + } + }; + + return sizes[size]; +}; + +/** + * Prüft ob prefers-reduced-motion aktiv ist + */ +const prefersReducedMotion = (): boolean => { + if (typeof window === 'undefined') return false; + return window.matchMedia('(prefers-reduced-motion: reduce)').matches; +}; + +// ===== STEP ICON KOMPONENTE ===== +interface StepIconProps { + stepIndex: number; + currentStep: number; + size: StepSetupProps['size']; + animated: boolean; +} + +const StepNumber: React.FC<{ number: number; isCurrent?: boolean; isCompleted?: boolean }> = ({ + number, + isCurrent = false, + isCompleted = false +}) => { + const baseClasses = ` + w-6 h-6 + flex items-center justify-center + rounded-full text-xs font-medium + transition-all duration-200 + `; + + if (isCompleted) { + return ( +
+ ✓ +
+ ); + } + + if (isCurrent) { + return ( +
+ {number} +
+ ); + } + + return ( +
+ {number} +
+ ); +}; + +const StepIcon: React.FC = ({ + stepIndex, + currentStep, + size, + animated +}) => { + const isCompleted = stepIndex < currentStep; + const isCurrent = stepIndex === currentStep; + + const sizeClasses = getSizeClasses(size); + const animationConfig = getAnimationConfig(animated); + const shouldAnimate = animated && !prefersReducedMotion(); + + const baseClasses = ` + ${sizeClasses.step} + flex items-center justify-center + rounded-full border-2 font-medium + transition-all duration-200 + `; + + if (isCompleted) { + const completedClasses = ` + ${baseClasses} + border-blue-500 bg-white + `; + + const iconContent = shouldAnimate ? ( + + + + ) : ( + + ); + + return ( +
+ {iconContent} +
+ ); + } + + if (isCurrent) { + const currentClasses = ` + ${baseClasses} + border-blue-500 bg-white + `; + + const stepNumber = shouldAnimate ? ( + + + + ) : ( + + ); + + return
{stepNumber}
; + } + + const upcomingClasses = ` + ${baseClasses} + border-gray-300 bg-white + `; + + return ( +
+ +
+ ); +}; + +// ===== HAUPTKOMPONENTE ===== + +/** + * Eine zugängliche, animierte Step/Progress-Komponente mit Unterstützung für + * kontrollierte und unkontrollierte Verwendung. + * + * @example + * ```tsx + * console.log('Step changed:', index)} + * /> + * ``` + */ +const StepSetup: React.FC = (props) => { + const { + steps, + orientation = 'horizontal', + clickable = true, + size = 'md', + animated = true, + className = '' + } = props; + + const { + currentStep, + goToStep + } = useStepSetup(props); + + const listId = useId(); + const shouldAnimate = animated && !prefersReducedMotion(); + const sizeClasses = getSizeClasses(size); + + // Fallback für leere Steps + if (!steps || steps.length === 0) { + return ( +
+ No steps available +
+ ); + } + + // Tastatur-Navigation Handler + const handleKeyDown = ( + event: KeyboardEvent, + stepIndex: number + ) => { + if (!clickable) return; + + const isHorizontal = orientation === 'horizontal'; + + switch (event.key) { + case 'Enter': + case ' ': + event.preventDefault(); + goToStep(stepIndex); + break; + + case 'ArrowRight': + case 'ArrowDown': + if ((isHorizontal && event.key === 'ArrowRight') || + (!isHorizontal && event.key === 'ArrowDown')) { + event.preventDefault(); + const nextStep = Math.min(stepIndex + 1, steps.length - 1); + goToStep(nextStep); + } + break; + + case 'ArrowLeft': + case 'ArrowUp': + if ((isHorizontal && event.key === 'ArrowLeft') || + (!isHorizontal && event.key === 'ArrowUp')) { + event.preventDefault(); + const prevStep = Math.max(stepIndex - 1, 0); + goToStep(prevStep); + } + break; + + case 'Home': + event.preventDefault(); + goToStep(0); + break; + + case 'End': + event.preventDefault(); + goToStep(steps.length - 1); + break; + } + }; + + // Container-Klassen basierend auf Ausrichtung + const containerClasses = ` + flex ${orientation === 'vertical' ? 'flex-col' : 'flex-row'} + ${orientation === 'horizontal' ? 'items-center justify-center gap-8' : 'gap-6'} + ${className} + `; + + const StepContent = shouldAnimate ? motion.div : 'div'; + + return ( + + + + ); +}; + +export default StepSetup; \ No newline at end of file diff --git a/frontend/src/pages/Setup/Setup.tsx b/frontend/src/pages/Setup/Setup.tsx index 932676a..3c5a2d7 100644 --- a/frontend/src/pages/Setup/Setup.tsx +++ b/frontend/src/pages/Setup/Setup.tsx @@ -1,12 +1,27 @@ -// frontend/src/pages/Setup/Setup.tsx - UPDATED import React, { useState } from 'react'; import { useAuth } from '../../contexts/AuthContext'; +import StepSetup, { Step } from '../../components/StepSetup/StepSetup'; const API_BASE_URL = '/api'; -const Setup: React.FC = () => { - const [step, setStep] = useState(1); - const [formData, setFormData] = useState({ +// ===== TYP-DEFINITIONEN ===== +interface SetupFormData { + password: string; + confirmPassword: string; + firstname: string; + lastname: string; +} + +interface SetupStep { + id: string; + title: string; + subtitle?: string; +} + +// ===== HOOK FÜR SETUP-LOGIK ===== +const useSetup = () => { + const [currentStep, setCurrentStep] = useState(0); + const [formData, setFormData] = useState({ password: '', confirmPassword: '', firstname: '', @@ -16,15 +31,26 @@ const Setup: React.FC = () => { const [error, setError] = useState(''); const { checkSetupStatus } = useAuth(); - const handleInputChange = (e: React.ChangeEvent) => { - const { name, value } = e.target; - setFormData(prev => ({ - ...prev, - [name]: value - })); - }; + const steps: SetupStep[] = [ + { + id: 'password-setup', + title: 'Passwort erstellen', + subtitle: 'Legen Sie ein sicheres Passwort fest' + }, + { + id: 'profile-setup', + title: 'Profilinformationen', + subtitle: 'Geben Sie Ihre persönlichen Daten ein' + }, + { + id: 'confirmation', + title: 'Bestätigung', + subtitle: 'Setup abschließen' + } + ]; - const validateStep1 = () => { + // ===== VALIDIERUNGS-FUNKTIONEN ===== + const validateStep1 = (): boolean => { if (formData.password.length < 6) { setError('Das Passwort muss mindestens 6 Zeichen lang sein.'); return false; @@ -36,7 +62,7 @@ const Setup: React.FC = () => { return true; }; - const validateStep2 = () => { + const validateStep2 = (): boolean => { if (!formData.firstname.trim()) { setError('Bitte geben Sie einen Vornamen ein.'); return false; @@ -48,21 +74,66 @@ const Setup: React.FC = () => { return true; }; - const handleNext = () => { - setError(''); - if (step === 1 && validateStep1()) { - setStep(2); - } else if (step === 2 && validateStep2()) { - handleSubmit(); + const validateCurrentStep = (stepIndex: number): boolean => { + switch (stepIndex) { + case 0: + return validateStep1(); + case 1: + return validateStep2(); + default: + return true; } }; - const handleBack = () => { + // ===== NAVIGATIONS-FUNKTIONEN ===== + const goToNextStep = async (): Promise => { setError(''); - setStep(1); + + if (!validateCurrentStep(currentStep)) { + return; + } + + // Wenn wir beim letzten Schritt sind, Submit ausführen + if (currentStep === steps.length - 1) { + await handleSubmit(); + return; + } + + // Ansonsten zum nächsten Schritt gehen + setCurrentStep(prev => prev + 1); }; - const handleSubmit = async () => { + const goToPrevStep = (): void => { + setError(''); + if (currentStep > 0) { + setCurrentStep(prev => prev - 1); + } + }; + + const handleStepChange = (stepIndex: number): void => { + setError(''); + + // Nur erlauben, zu bereits validierten Schritten zu springen + // oder zum nächsten Schritt nach dem aktuellen + if (stepIndex <= currentStep + 1) { + // Vor dem Wechsel validieren + if (stepIndex > currentStep && !validateCurrentStep(currentStep)) { + return; + } + setCurrentStep(stepIndex); + } + }; + + // ===== FORM HANDLER ===== + const handleInputChange = (e: React.ChangeEvent): void => { + const { name, value } = e.target; + setFormData(prev => ({ + ...prev, + [name]: value + })); + }; + + const handleSubmit = async (): Promise => { try { setLoading(true); setError(''); @@ -102,8 +173,8 @@ const Setup: React.FC = () => { } }; - // Helper to display generated email preview - const getEmailPreview = () => { + // ===== HELPER FUNCTIONS ===== + const getEmailPreview = (): string => { if (!formData.firstname.trim() || !formData.lastname.trim()) { return 'vorname.nachname@sp.de'; } @@ -113,6 +184,299 @@ const Setup: React.FC = () => { return `${cleanFirstname}.${cleanLastname}@sp.de`; }; + const isStepCompleted = (stepIndex: number): boolean => { + switch (stepIndex) { + case 0: + return formData.password.length >= 6 && + formData.password === formData.confirmPassword; + case 1: + return !!formData.firstname.trim() && !!formData.lastname.trim(); + default: + return false; + } + }; + + return { + // State + currentStep, + formData, + loading, + error, + steps, + + // Actions + goToNextStep, + goToPrevStep, + handleStepChange, + handleInputChange, + + // Helpers + getEmailPreview, + isStepCompleted + }; +}; + +// ===== STEP-INHALTS-KOMPONENTEN ===== +interface StepContentProps { + formData: SetupFormData; + onInputChange: (e: React.ChangeEvent) => void; + getEmailPreview: () => string; + currentStep: number; +} + +const Step1Content: React.FC = ({ + formData, + onInputChange +}) => ( +
+
+ + +
+ +
+ + +
+
+); + +const Step2Content: React.FC = ({ + formData, + onInputChange, + getEmailPreview +}) => ( +
+
+ + +
+ +
+ + +
+ +
+ +
+ {getEmailPreview()} +
+
+ Die E-Mail wird automatisch aus Vor- und Nachname generiert +
+
+
+); + +const Step3Content: React.FC = ({ + formData, + getEmailPreview +}) => ( +
+
+

+ Zusammenfassung +

+ +
+
+ E-Mail: + {getEmailPreview()} +
+
+ Vorname: + {formData.firstname || '-'} +
+
+ Nachname: + {formData.lastname || '-'} +
+
+
+ +
+ 💡 Wichtig: Nach dem Setup können Sie sich mit Ihrer + automatisch generierten E-Mail anmelden. +
+
+); + +// ===== HAUPTKOMPONENTE ===== +const Setup: React.FC = () => { + const { + currentStep, + formData, + loading, + error, + steps, + goToNextStep, + goToPrevStep, + handleStepChange, + handleInputChange, + getEmailPreview + } = useSetup(); + + const renderStepContent = (): React.ReactNode => { + const stepProps = { + formData, + onInputChange: handleInputChange, + getEmailPreview, + currentStep + }; + + switch (currentStep) { + case 0: + return ; + case 1: + return ; + case 2: + return ; + default: + return null; + } + }; + + const getNextButtonText = (): string => { + if (loading) return '⏳ Wird verarbeitet...'; + + switch (currentStep) { + case 0: + return 'Weiter →'; + case 1: + return 'Weiter →'; + case 2: + return 'Setup abschließen'; + default: + return 'Weiter →'; + } + }; + return (
{ borderRadius: '12px', boxShadow: '0 10px 30px rgba(0,0,0,0.1)', width: '100%', - maxWidth: '500px', + maxWidth: '600px', border: '1px solid #e9ecef' }}> -
+

{

Richten Sie Ihren Administrator-Account ein

+ {/* Aktueller Schritt Titel und Beschreibung */} +
+

+ {steps[currentStep].title} +

+ {steps[currentStep].subtitle && ( +

+ {steps[currentStep].subtitle} +

+ )} +
+ + {/* StepSetup Komponente - nur die Steps ohne Beschreibung */} +
+ ({ ...step, subtitle: undefined }))} + current={currentStep} + onChange={handleStepChange} + orientation="horizontal" + clickable={true} + size="md" + animated={true} + /> +
+ + {/* Fehleranzeige */} {error && (
{
)} - {step === 1 && ( -
-
- - -
- -
- - -
-
- )} - - {step === 2 && ( -
-
- - -
- -
- - -
- -
- -
- {getEmailPreview()} -
-
- Die E-Mail wird automatisch aus Vor- und Nachname generiert -
-
-
- )} + {/* Schritt-Inhalt */} +
+ {renderStepContent()} +
+ {/* Navigations-Buttons */}
- {step === 2 && ( - - )} +
- {step === 2 && ( + {/* Zusätzliche Informationen */} + {currentStep === 2 && !loading && (
- 💡 Nach dem erfolgreichen Setup werden Sie zur Anmeldeseite weitergeleitet, - wo Sie sich mit Ihrer automatisch generierten E-Mail anmelden können. + Überprüfen Sie Ihre Daten, bevor Sie das Setup abschließen
)}
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 66aa503..f765ea1 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -23,7 +23,7 @@ export default defineConfig(({ mode }) => { server: { port: 3003, host: true, - open: isDevelopment, + //open: isDevelopment, proxy: { '/api': { target: 'http://localhost:3002', diff --git a/package-lock.json b/package-lock.json index 7114e1f..ceb0797 100644 --- a/package-lock.json +++ b/package-lock.json @@ -228,27 +228,6 @@ "dev": true, "license": "MIT" }, - "backend/node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "backend/node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "backend/node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, "backend/node_modules/@types/jest": { "version": "29.5.14", "dev": true, @@ -280,7 +259,6 @@ "backend/node_modules/@types/node": { "version": "24.7.0", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.14.0" } @@ -322,29 +300,11 @@ "@types/node": "*" } }, - "backend/node_modules/@types/stack-utils": { - "version": "2.0.3", - "dev": true, - "license": "MIT" - }, "backend/node_modules/@types/uuid": { "version": "9.0.8", "dev": true, "license": "MIT" }, - "backend/node_modules/@types/yargs": { - "version": "17.0.33", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "backend/node_modules/@types/yargs-parser": { - "version": "21.0.3", - "dev": true, - "license": "MIT" - }, "backend/node_modules/abbrev": { "version": "1.1.1", "license": "ISC", @@ -395,28 +355,6 @@ "node": ">=8" } }, - "backend/node_modules/ansi-regex": { - "version": "5.0.1", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "backend/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "backend/node_modules/aproba": { "version": "2.1.0", "license": "ISC", @@ -510,17 +448,6 @@ "concat-map": "0.0.1" } }, - "backend/node_modules/braces": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "backend/node_modules/buffer": { "version": "5.7.1", "funding": [ @@ -575,21 +502,6 @@ "node": ">= 10" } }, - "backend/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "backend/node_modules/chownr": { "version": "2.0.0", "license": "ISC", @@ -619,22 +531,6 @@ "node": ">=6" } }, - "backend/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "backend/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, "backend/node_modules/color-support": { "version": "1.1.3", "license": "ISC", @@ -786,14 +682,6 @@ "@esbuild/win32-x64": "0.25.11" } }, - "backend/node_modules/escape-string-regexp": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "backend/node_modules/expand-template": { "version": "2.0.3", "license": "(MIT OR WTFPL)", @@ -820,17 +708,6 @@ "version": "1.0.0", "license": "MIT" }, - "backend/node_modules/fill-range": { - "version": "7.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "backend/node_modules/fs-constants": { "version": "1.0.0", "license": "MIT" @@ -902,19 +779,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "backend/node_modules/graceful-fs": { - "version": "4.2.11", - "devOptional": true, - "license": "ISC" - }, - "backend/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "backend/node_modules/has-unicode": { "version": "2.0.1", "license": "ISC", @@ -995,14 +859,6 @@ "node": ">=0.8.19" } }, - "backend/node_modules/indent-string": { - "version": "4.0.0", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, "backend/node_modules/infer-owner": { "version": "1.0.4", "license": "ISC", @@ -1034,14 +890,6 @@ "license": "MIT", "optional": true }, - "backend/node_modules/is-number": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, "backend/node_modules/isexe": { "version": "2.0.0", "license": "ISC", @@ -1233,18 +1081,6 @@ "node": ">= 0.6" } }, - "backend/node_modules/micromatch": { - "version": "4.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "backend/node_modules/mimic-response": { "version": "3.1.0", "license": "MIT", @@ -1572,11 +1408,6 @@ "rc": "cli.js" } }, - "backend/node_modules/react-is": { - "version": "18.3.1", - "dev": true, - "license": "MIT" - }, "backend/node_modules/readable-stream": { "version": "3.6.2", "license": "MIT", @@ -1680,14 +1511,6 @@ "simple-concat": "^1.0.0" } }, - "backend/node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "backend/node_modules/smart-buffer": { "version": "4.2.0", "license": "MIT", @@ -1756,17 +1579,6 @@ "node": ">= 8" } }, - "backend/node_modules/stack-utils": { - "version": "2.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "backend/node_modules/string_decoder": { "version": "1.3.0", "license": "MIT", @@ -1805,17 +1617,6 @@ "node": ">=0.10.0" } }, - "backend/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "backend/node_modules/tar": { "version": "6.2.1", "license": "ISC", @@ -1866,17 +1667,6 @@ "node": ">=8" } }, - "backend/node_modules/to-regex-range": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, "backend/node_modules/ts-node": { "version": "10.9.2", "dev": true, @@ -2034,6 +1824,11 @@ "react-router-dom": "^6.28.0" }, "devDependencies": { + "@storybook/react": "10.0.1", + "@testing-library/jest-dom": "6.9.1", + "@testing-library/react": "10.4.1", + "@testing-library/user-event": "14.6.1", + "@types/jest": "30.0.0", "@types/node": "20.19.23", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", @@ -2041,11 +1836,19 @@ "@vitejs/plugin-react": "^4.3.3", "babel-plugin-transform-remove-console": "6.9.4", "esbuild": "^0.21.0", + "framer-motion": "12.23.24", "terser": "5.44.0", "typescript": "^5.7.3", "vite": "^6.0.7" } }, + "node_modules/@adobe/css-tools": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "dev": true, @@ -2071,7 +1874,6 @@ "version": "7.28.5", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -2249,6 +2051,29 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.4.tgz", + "integrity": "sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-js-pure": "^3.43.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.27.2", "dev": true, @@ -2306,6 +2131,85 @@ "node": ">=12" } }, + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "dev": true, @@ -2393,6 +2297,231 @@ "win32" ] }, + "node_modules/@schichtenplaner/premium": { + "resolved": "premium", + "link": true + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/icons": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.6.0.tgz", + "integrity": "sha512-hcFZIjW8yQz8O8//2WTIXylm5Xsgc+lW9ISLgUk1xGmptIJQRdlhVIXCpSyLrQaaRiyhQRaVg7l3BD9S216BHw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" + } + }, + "node_modules/@storybook/react": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-10.0.1.tgz", + "integrity": "sha512-MtQ4G8q2wTe2E9zeuyAP/pZgwZEI+ijHZo8spndLdNF1gj+ihsdJguDS+ZAbfZSMNz0s2zroX4t+SKDSBbqBdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/react-dom-shim": "10.0.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "storybook": "^10.0.1", + "typescript": ">= 4.9.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-dom-shim": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-10.0.1.tgz", + "integrity": "sha512-fK6SLWKK0wsnBVRAjWwf+T7cMHXdgQ34Xk18QeAAXWJyT8UAb7x1QwdepOWBG2Gs2hVjJjD5ky/sRzK1L3kA9A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "storybook": "^10.0.1" + } + }, + "node_modules/@testing-library/dom": { + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.6", + "lz-string": "^1.4.4", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@testing-library/dom/node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@testing-library/dom/node_modules/@types/yargs": { + "version": "15.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", + "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@testing-library/dom/node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/dom/node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@testing-library/dom/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/react": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-10.4.1.tgz", + "integrity": "sha512-QX31fRDGLnOdBYoQ95VEOYgRahaPfsI+toOaYhlvuGNFQrcagZv/KLWCIctRGB0h1PTsQt3JpLBbbLGM63yy5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.3", + "@testing-library/dom": "^7.17.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@types/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "dev": true, @@ -2430,6 +2559,26 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@types/estree": { "version": "1.0.8", "dev": true, @@ -2440,11 +2589,48 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, "node_modules/@types/node": { "version": "20.19.23", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -2453,7 +2639,6 @@ "version": "19.2.2", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -2485,6 +2670,30 @@ "@types/react-router": "*" } }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.34", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.34.tgz", + "integrity": "sha512-KExbHVa92aJpw9WDQvzBaGVE2/Pz+pLZQloT2hjL8IqsZnV62rlPOYvNnLmf/L2dyllfVUOVBj64M0z/46eR2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "dev": true, @@ -2504,6 +2713,96 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -2530,12 +2829,73 @@ "node": ">=0.4.0" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "license": "MIT" }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/babel-plugin-transform-remove-console": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", @@ -2590,6 +2950,19 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.27.0", "dev": true, @@ -2608,7 +2981,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", @@ -2687,6 +3059,88 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 16" + } + }, + "node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -2735,6 +3189,25 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, + "node_modules/core-js-pure": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.46.0.tgz", + "integrity": "sha512-NMCW30bHNofuhwLhYPt66OLOKTMbOhgTTatKVbaQC3KRHpTCiRIBYvtshr+NBYSnBxwAFhjW/RfJ0XbIjS16rw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, "node_modules/csstype": { "version": "3.1.3", "dev": true, @@ -2766,6 +3239,17 @@ } } }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2785,6 +3269,13 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2900,6 +3391,42 @@ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -2909,6 +3436,24 @@ "node": ">= 0.6" } }, + "node_modules/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/express": { "version": "4.21.2", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", @@ -3017,6 +3562,19 @@ } } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/finalhandler": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", @@ -3059,6 +3617,34 @@ "node": ">= 0.6" } }, + "node_modules/framer-motion": { + "version": "12.23.24", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz", + "integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "motion-dom": "^12.23.23", + "motion-utils": "^12.23.6", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -3138,6 +3724,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -3199,6 +3802,16 @@ "node": ">=0.10.0" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -3223,6 +3836,112 @@ "node": ">= 0.10" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.2.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "dev": true, @@ -3256,6 +3975,14 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/lru-cache": { "version": "5.1.1", "dev": true, @@ -3264,6 +3991,27 @@ "yallist": "^3.0.2" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -3300,6 +4048,33 @@ "node": ">= 0.6" } }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -3333,6 +4108,33 @@ "node": ">= 0.6" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/motion-dom": { + "version": "12.23.23", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz", + "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "motion-utils": "^12.23.6" + } + }, + "node_modules/motion-utils": { + "version": "12.23.6", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz", + "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==", + "dev": true, + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "license": "MIT" @@ -3407,6 +4209,17 @@ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "license": "MIT" }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 14.16" + } + }, "node_modules/picocolors": { "version": "1.1.1", "dev": true, @@ -3416,7 +4229,6 @@ "version": "4.0.3", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -3451,6 +4263,34 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -3506,7 +4346,6 @@ "node_modules/react": { "version": "19.2.0", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -3514,7 +4353,6 @@ "node_modules/react-dom": { "version": "19.2.0", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -3522,6 +4360,13 @@ "react": "^19.2.0" } }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/react-refresh": { "version": "0.17.0", "dev": true, @@ -3558,6 +4403,38 @@ "react-dom": ">=16.8" } }, + "node_modules/recast": { + "version": "0.23.11", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", + "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/rollup": { "version": "4.52.5", "dev": true, @@ -3781,6 +4658,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -3810,6 +4697,19 @@ "source-map": "^0.6.0" } }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -3819,13 +4719,88 @@ "node": ">= 0.8" } }, + "node_modules/storybook": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-10.0.1.tgz", + "integrity": "sha512-WQMfNsbyHO8fx5bLatsLATzvFwzG42xHnq8W9s2HzjhGzQ2Pp77k7nRWXMuRNvvv+4ypKhJdqeDl8S9kwWuz2A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/icons": "^1.6.0", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/user-event": "^14.6.1", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/spy": "3.2.4", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0", + "recast": "^0.23.5", + "semver": "^7.6.2", + "ws": "^8.18.0" + }, + "bin": { + "storybook": "dist/bin/dispatcher.js" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, + "node_modules/storybook/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/terser": { "version": "5.44.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", @@ -3839,6 +4814,14 @@ "node": ">=10" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/tinyglobby": { "version": "0.2.15", "dev": true, @@ -3854,6 +4837,41 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -3863,6 +4881,13 @@ "node": ">=0.6" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -3880,7 +4905,6 @@ "version": "5.9.3", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3963,7 +4987,6 @@ "version": "6.4.1", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -4088,6 +5111,29 @@ "@esbuild/win32-x64": "0.25.11" } }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yallist": { "version": "3.1.1", "dev": true, @@ -4096,7 +5142,6 @@ "premium": { "name": "@schichtenplaner/premium", "version": "1.0.0", - "extraneous": true, "workspaces": [ "backendPRO", "frontendPRO"