diff --git a/.github/workflows/issues.yaml b/.github/workflows/issues.yaml index 2af9fb755..8be35b43c 100644 --- a/.github/workflows/issues.yaml +++ b/.github/workflows/issues.yaml @@ -8,9 +8,10 @@ jobs: label: runs-on: ubuntu-latest steps: + - name: Checkout Repository + uses: actions/checkout@v4 - name: Run Script uses: actions/github-script@v7 with: script: | require('./.github/scripts/issues.cjs')() - \ No newline at end of file diff --git a/README.md b/README.md index f68ce7d7e..1d52db986 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@

Open Data Capture

- A modern, user-friendly web application for standardized data capture in medical research + An electronic data capture platform designed for administering remote and in-person clinical instruments, including both interactive tasks and forms
Explore the docs » diff --git a/apps/gateway/src/Root.tsx b/apps/gateway/src/Root.tsx index 2af3a4d7e..2b71ff863 100644 --- a/apps/gateway/src/Root.tsx +++ b/apps/gateway/src/Root.tsx @@ -1,8 +1,8 @@ -import { NotificationHub, useNotificationsStore } from '@douglasneuroinformatics/ui'; +import { BaseLanguageToggle, NotificationHub, ThemeToggle, useNotificationsStore } from '@douglasneuroinformatics/ui'; import type { UpdateAssignmentData } from '@open-data-capture/common/assignment'; import { $Json } from '@open-data-capture/common/core'; import { InstrumentRenderer } from '@open-data-capture/instrument-renderer'; -import { Navbar } from '@open-data-capture/react-core'; +import { Branding } from '@open-data-capture/react-core'; import axios from 'axios'; import { useTranslation } from 'react-i18next'; @@ -43,8 +43,14 @@ export const Root = ({ bundle, id, token }: RootProps) => { return (

-
- +
+
+ +
+ + +
+
diff --git a/apps/web/package.json b/apps/web/package.json index 6c8060bae..4ff4f61ae 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -34,10 +34,8 @@ "@open-data-capture/instrument-renderer": "workspace:*", "@open-data-capture/instrument-utils": "workspace:*", "@open-data-capture/react-core": "workspace:*", - "@react-spring/web": "^9.7.3", "@tanstack/react-query": "^5.17.9", "@tanstack/react-query-devtools": "^5.17.9", - "@use-gesture/react": "^10.3.0", "axios": "^1.6.5", "clsx": "^2.1.0", "framer-motion": "^10.18.0", diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index c82ad3b63..1c38fe9b0 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -7,7 +7,6 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { ErrorBoundary } from 'react-error-boundary'; import { Router } from '@/Router'; -import { ActiveVisit } from '@/components/ActiveVisit'; import { LoadingFallback } from '@/components/LoadingFallback'; import { SetupProvider } from '@/features/setup'; import { queryClient } from '@/services/react-query'; @@ -21,7 +20,6 @@ export const App = () => { }> - diff --git a/apps/web/src/components/ActiveVisit/ActiveVisit.stories.tsx b/apps/web/src/components/ActiveVisit/ActiveVisit.stories.tsx deleted file mode 100644 index c338476d5..000000000 --- a/apps/web/src/components/ActiveVisit/ActiveVisit.stories.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { useEffect } from 'react'; - -import type { Meta, StoryObj } from '@storybook/react'; - -import { useActiveVisitStore } from '@/stores/active-visit-store'; - -import { ActiveVisit } from './ActiveVisit'; - -type Story = StoryObj; - -export default { - component: ActiveVisit, - decorators: [ - (Story) => { - const { setActiveVisit } = useActiveVisitStore(); - useEffect(() => { - setActiveVisit({ - createdAt: new Date(), - date: new Date(), - groupId: null, - id: '123', - subject: { - createdAt: new Date(), - dateOfBirth: new Date('2000-01-01'), - firstName: 'John', - groupIds: [], - id: '12345', - lastName: 'Appleseed', - sex: 'MALE', - updatedAt: new Date() - }, - subjectId: '12345', - updatedAt: new Date() - }); - }, []); - return ; - } - ] -} as Meta; - -export const Default: Story = {}; diff --git a/apps/web/src/components/ActiveVisit/ActiveVisit.tsx b/apps/web/src/components/ActiveVisit/ActiveVisit.tsx deleted file mode 100644 index 375074b35..000000000 --- a/apps/web/src/components/ActiveVisit/ActiveVisit.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import React, { useState } from 'react'; - -import { toBasicISOString } from '@douglasneuroinformatics/utils'; -import { MinusCircleIcon, XCircleIcon } from '@heroicons/react/24/solid'; -import { toLowerCase } from '@open-data-capture/common/core'; -import { animated, useSpring } from '@react-spring/web'; -import { useDrag } from '@use-gesture/react'; -import { useTranslation } from 'react-i18next'; - -import { useActiveVisitStore } from '@/stores/active-visit-store'; - -export const ActiveVisit = () => { - const { activeVisit, setActiveVisit } = useActiveVisitStore(); - const [isHidden, setIsHidden] = useState(false); - const { t } = useTranslation(['core', 'common']); - const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 })); - - const bind = useDrag( - ({ down, offset: [ox, oy] }) => { - void api.start({ immediate: down, x: ox, y: oy }); - }, - { - bounds: document.body, - rubberband: true - } - ); - - if (!activeVisit) { - return null; - } - - return ( - -
- - -
- {isHidden && ( - -

{t('common:activeVisit')}

-
- - {t('identificationData.firstName.label')}: {activeVisit.subject.firstName} - - - {t('identificationData.lastName.label')}: {activeVisit.subject.lastName} - - - {t('identificationData.dateOfBirth.label')}: {toBasicISOString(activeVisit.subject.dateOfBirth)} - - - {t('identificationData.sex.label')}: {t(`identificationData.sex.${toLowerCase(activeVisit.subject.sex)}`)} - -
- )} -
- ); -}; diff --git a/apps/web/src/components/ActiveVisit/index.ts b/apps/web/src/components/ActiveVisit/index.ts deleted file mode 100644 index 21f4fd7b5..000000000 --- a/apps/web/src/components/ActiveVisit/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './ActiveVisit'; diff --git a/apps/web/src/components/Layout/Layout.tsx b/apps/web/src/components/Layout/Layout.tsx index 0dfad912a..c3c8972a2 100644 --- a/apps/web/src/components/Layout/Layout.tsx +++ b/apps/web/src/components/Layout/Layout.tsx @@ -1,73 +1,17 @@ -import { useEffect, useState } from 'react'; - -import { AdjustmentsHorizontalIcon, ChartBarIcon, EyeIcon, UserPlusIcon } from '@heroicons/react/24/solid'; -import { type NavItem, Navbar } from '@open-data-capture/react-core'; -import { useTranslation } from 'react-i18next'; -import { Outlet, useLocation, useNavigate } from 'react-router-dom'; - -import { useAuthStore } from '@/stores/auth-store'; +import { Outlet } from 'react-router-dom'; import { Footer } from './Footer'; +import { Navbar } from './Navbar'; import { Sidebar } from './Sidebar'; export const Layout = () => { - const { currentUser } = useAuthStore(); - const [navItems, setNavItems] = useState([]); - const { i18n, t } = useTranslation('layout'); - const navigate = useNavigate(); - const location = useLocation(); - - useEffect(() => { - const items: NavItem[] = [ - { - 'data-cy': 'overview', - icon: ChartBarIcon, - id: '/overview', - label: t('navLinks.overview') - } - ]; - if (currentUser?.ability.can('create', 'Visit')) { - items.push({ - 'data-cy': 'add-visit', - icon: UserPlusIcon, - id: '/visits/add-visit', - label: t('navLinks.addVisit') - }); - } - if (currentUser?.ability.can('read', 'Subject') && currentUser.ability.can('read', 'InstrumentRecord')) { - items.push({ - 'data-cy': 'view-subjects', - icon: EyeIcon, - id: '/subjects', - label: t(`navLinks.viewSubjects`) - }); - } - if (currentUser?.ability.can('manage', 'Instrument')) { - items.push({ - 'data-cy': 'manage-instrument', - icon: AdjustmentsHorizontalIcon, - id: '/instruments/manage-instruments', - label: t('navLinks.manageInstruments') - }); - } - if (currentUser?.ability.can('create', 'InstrumentRecord')) { - items.push({ - 'data-cy': 'view-instrument', - icon: EyeIcon, - id: '/instruments/available-instruments', - label: t('navLinks.availableInstruments') - }); - } - setNavItems(items); - }, [currentUser, i18n.resolvedLanguage]); - return (
-
- +
+
-
- +
+
diff --git a/packages/react-core/src/components/Navbar/MobileSlider.tsx b/apps/web/src/components/Layout/MobileSlider.tsx similarity index 71% rename from packages/react-core/src/components/Navbar/MobileSlider.tsx rename to apps/web/src/components/Layout/MobileSlider.tsx index b499f36ab..8104a5b19 100644 --- a/packages/react-core/src/components/Navbar/MobileSlider.tsx +++ b/apps/web/src/components/Layout/MobileSlider.tsx @@ -1,25 +1,22 @@ import { Slider, ThemeToggle } from '@douglasneuroinformatics/ui'; +import { Branding } from '@open-data-capture/react-core'; +import { useTranslation } from 'react-i18next'; -import { Branding } from '../Branding'; import { Navigation } from './Navigation'; -import type { NavI18Next, NavItem } from './types'; - export type MobileSliderProps = { - activeItemId?: string; - i18n: NavI18Next; isOpen: boolean; - items: NavItem[]; onNavigate?: (id: string) => void; setIsOpen: (isOpen: boolean) => void; }; -export const MobileSlider = ({ activeItemId, i18n, isOpen, items, onNavigate, setIsOpen }: MobileSliderProps) => { +export const MobileSlider = ({ isOpen, onNavigate, setIsOpen }: MobileSliderProps) => { + const { i18n } = useTranslation(); return ( }>
- +
+ ); +}; diff --git a/apps/web/src/components/Layout/Navbar.tsx b/apps/web/src/components/Layout/Navbar.tsx new file mode 100644 index 000000000..41bb1e11e --- /dev/null +++ b/apps/web/src/components/Layout/Navbar.tsx @@ -0,0 +1,47 @@ +import React, { useEffect, useState } from 'react'; + +import { useMediaQuery } from '@douglasneuroinformatics/ui'; +import { Bars3Icon } from '@heroicons/react/24/outline'; +import { Branding } from '@open-data-capture/react-core'; + +import { MobileSlider } from './MobileSlider'; + +export const Navbar = () => { + const [isOpen, setIsOpen] = useState(false); + + // This is to prevent ugly styling when resizing the viewport + const isDesktop = useMediaQuery('(min-width: 768px)'); + + useEffect(() => { + if (isDesktop) { + setIsOpen(false); + } + }, [isDesktop]); + + return ( + +
+
+
+ + +
+
+
+ { + setIsOpen(false); + }} + /> +
+ ); +}; diff --git a/apps/web/src/components/Layout/Navigation.tsx b/apps/web/src/components/Layout/Navigation.tsx new file mode 100644 index 000000000..21cf0bc4a --- /dev/null +++ b/apps/web/src/components/Layout/Navigation.tsx @@ -0,0 +1,158 @@ +import { useEffect, useState } from 'react'; + +import { Button, Modal, cn } from '@douglasneuroinformatics/ui'; +import { + ChartBarIcon, + ChartPieIcon, + ComputerDesktopIcon, + EyeIcon, + StopIcon, + UserPlusIcon +} from '@heroicons/react/24/solid'; +import { useTranslation } from 'react-i18next'; +import { useLocation, useNavigate } from 'react-router-dom'; + +import { useActiveVisitStore } from '@/stores/active-visit-store'; +import { useAuthStore } from '@/stores/auth-store'; + +import { NavButton } from './NavButton'; + +import type { NavItem } from './types'; + +export type NavigationProps = { + btn?: { + activeClassName: string; + className: string; + }; + isAlwaysDark: boolean; + onNavigate?: (id: string) => void; + orientation: 'horizontal' | 'vertical'; +}; + +export const Navigation = ({ btn, isAlwaysDark, onNavigate, orientation }: NavigationProps) => { + const { currentUser } = useAuthStore(); + const { activeVisit, setActiveVisit } = useActiveVisitStore(); + const [isEndVisitModalOpen, setIsEndVisitModalOpen] = useState(false); + + const [navItems, setNavItems] = useState([]); + const { i18n, t } = useTranslation(['layout', 'core']); + const navigate = useNavigate(); + const location = useLocation(); + + useEffect(() => { + const globalItems: NavItem[] = [ + { + 'data-cy': 'overview', + icon: ChartBarIcon, + id: '/overview', + label: t('navLinks.overview') + } + ]; + if (currentUser?.ability.can('read', 'Subject') && currentUser.ability.can('read', 'InstrumentRecord')) { + globalItems.push({ + 'data-cy': 'view-subjects', + icon: ChartPieIcon, + id: '/subjects', + label: t(`navLinks.viewSubjects`) + }); + } + const visitItems: NavItem[] = []; + if (currentUser?.ability.can('create', 'Visit')) { + visitItems.push({ + 'data-cy': 'add-visit', + disabled: activeVisit !== null, + icon: UserPlusIcon, + id: '/visits/add-visit', + label: t('navLinks.addVisit') + }); + } + if (currentUser?.ability.can('create', 'InstrumentRecord')) { + visitItems.push({ + 'data-cy': 'view-instrument', + disabled: activeVisit === null, + icon: ComputerDesktopIcon, + id: '/instruments/available-instruments', + label: t('navLinks.availableInstruments') + }); + } + if (currentUser?.ability.can('read', 'Subject') && currentUser.ability.can('read', 'InstrumentRecord')) { + visitItems.push({ + disabled: activeVisit === null, + icon: EyeIcon, + id: `/subjects/${activeVisit?.subjectId}/table`, + label: t('navLinks.viewCurrentSubject') + }); + } + setNavItems([globalItems, visitItems]); + }, [activeVisit, currentUser, i18n.resolvedLanguage]); + + return ( + <> + + setIsEndVisitModalOpen(false)}> +

{t('endVisitModal.message')}

+
+
+
+ + ); +}; diff --git a/apps/web/src/components/Layout/Sidebar.tsx b/apps/web/src/components/Layout/Sidebar.tsx index 54b66956f..4af7b00fb 100644 --- a/apps/web/src/components/Layout/Sidebar.tsx +++ b/apps/web/src/components/Layout/Sidebar.tsx @@ -1,29 +1,21 @@ import { ThemeToggle } from '@douglasneuroinformatics/ui'; -import { Branding, Navigation } from '@open-data-capture/react-core'; -import type { NavItem } from '@open-data-capture/react-core'; +import { Branding } from '@open-data-capture/react-core'; +import { Navigation } from './Navigation'; import { UserDropup } from './UserDropup'; -export type SidebarProps = { - activeItemId: string; - items: NavItem[]; - onNavigate: (id: string) => void; -}; - -export const Sidebar = ({ activeItemId, items, onNavigate }: SidebarProps) => { +export const Sidebar = () => { return (
- +

diff --git a/packages/react-core/src/components/Navbar/types.ts b/apps/web/src/components/Layout/types.ts similarity index 50% rename from packages/react-core/src/components/Navbar/types.ts rename to apps/web/src/components/Layout/types.ts index 62b0cc9fc..d29a8a601 100644 --- a/packages/react-core/src/components/Navbar/types.ts +++ b/apps/web/src/components/Layout/types.ts @@ -1,13 +1,7 @@ -import type { Promisable } from 'type-fest'; - export type NavItem = { [key: `data-${string}`]: unknown; + disabled?: boolean; icon?: React.ComponentType, 'ref'>>; id: string; label: string; }; - -export type NavI18Next = { - changeLanguage: (lang: string) => Promisable; - resolvedLanguage?: string; -}; diff --git a/apps/web/src/features/instruments/components/InstrumentShowcase/InstrumentShowcase.tsx b/apps/web/src/features/instruments/components/InstrumentShowcase/InstrumentShowcase.tsx index 8e530281b..15e8d5147 100644 --- a/apps/web/src/features/instruments/components/InstrumentShowcase/InstrumentShowcase.tsx +++ b/apps/web/src/features/instruments/components/InstrumentShowcase/InstrumentShowcase.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; -import { SearchBar, SelectDropdown, useNotificationsStore } from '@douglasneuroinformatics/ui'; +import { SearchBar, SelectDropdown } from '@douglasneuroinformatics/ui'; import type { SelectOption } from '@douglasneuroinformatics/ui'; import type { UnilingualInstrumentSummary } from '@open-data-capture/common/instrument'; import { motion } from 'framer-motion'; @@ -8,7 +8,6 @@ import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { useInstrumentSummariesQuery } from '@/hooks/useInstrumentSummariesQuery'; -import { useActiveVisitStore } from '@/stores/active-visit-store'; import { InstrumentCard } from '../InstrumentCard'; @@ -22,9 +21,6 @@ export const InstrumentsShowcase = () => { const [selectedTags, setSelectedTags] = useState([]); const [searchTerm, setSearchTerm] = useState(''); - const { activeVisit } = useActiveVisitStore(); - const notifications = useNotificationsStore(); - const languageOptions = [ { key: 'en', @@ -100,14 +96,7 @@ export const InstrumentsShowcase = () => { { - if (activeVisit) { - navigate(`/instruments/render/${instrument.id}`, { state: { summary: instrument } }); - } else { - notifications.addNotification({ - message: t('instruments:available.nullActiveVisitError'), - type: 'info' - }); - } + navigate(`/instruments/render/${instrument.id}`, { state: { summary: instrument } }); }} /> diff --git a/apps/web/src/features/instruments/index.tsx b/apps/web/src/features/instruments/index.tsx index 8b5423f69..46da0cabb 100644 --- a/apps/web/src/features/instruments/index.tsx +++ b/apps/web/src/features/instruments/index.tsx @@ -4,15 +4,10 @@ import type { RouteObject } from 'react-router-dom'; import { AvailableInstrumentsPage } from './pages/AvailableInstrumentsPage'; import { InstrumentRenderPage } from './pages/InstrumentRenderPage'; -import { ManageInstrumentsPage } from './pages/ManageInstrumentsPage'; export const instrumentsRoute: RouteObject = { path: 'instruments', children: [ - { - path: 'manage-instruments', - element: - }, { path: 'available-instruments', element: diff --git a/apps/web/src/features/instruments/pages/ManageInstrumentsPage.tsx b/apps/web/src/features/instruments/pages/ManageInstrumentsPage.tsx deleted file mode 100644 index a2e003f18..000000000 --- a/apps/web/src/features/instruments/pages/ManageInstrumentsPage.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export const ManageInstrumentsPage = () => { - return null; -}; diff --git a/apps/web/src/features/overview/components/Disclaimer.tsx b/apps/web/src/features/overview/components/Disclaimer.tsx index f47ca8549..35c0cc78b 100644 --- a/apps/web/src/features/overview/components/Disclaimer.tsx +++ b/apps/web/src/features/overview/components/Disclaimer.tsx @@ -22,7 +22,7 @@ export const Disclaimer = ({ isRequired = import.meta.env.PROD }: DisclaimerProp return ( -

{t('disclaimer.message')}

+

{t('disclaimer.message')}

-
- {items && ( - - -
- - )} -
- - -
-
-
-
-
- {items && ( - { - onNavigate?.(id); - setIsOpen(false); - }} - /> - )} - - ); -}; diff --git a/packages/react-core/src/components/Navbar/Navigation.tsx b/packages/react-core/src/components/Navbar/Navigation.tsx deleted file mode 100644 index fac528e22..000000000 --- a/packages/react-core/src/components/Navbar/Navigation.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { cn } from '@douglasneuroinformatics/ui'; - -import type { NavItem } from './types'; - -export type NavigationProps = { - activeItemId?: string; - btn?: { - activeClassName: string; - className: string; - }; - items: NavItem[]; - onNavigate?: (id: string) => void; - orientation: 'horizontal' | 'vertical'; -}; - -export const Navigation = ({ activeItemId, btn, items, onNavigate, orientation }: NavigationProps) => { - return ( - - ); -}; diff --git a/packages/react-core/src/components/Navbar/index.ts b/packages/react-core/src/components/Navbar/index.ts deleted file mode 100644 index ac4bbf75a..000000000 --- a/packages/react-core/src/components/Navbar/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './Navbar'; -export * from './Navigation'; -export * from './types'; diff --git a/packages/react-core/src/index.ts b/packages/react-core/src/index.ts index 0b4182541..c9784c718 100644 --- a/packages/react-core/src/index.ts +++ b/packages/react-core/src/index.ts @@ -2,4 +2,3 @@ export * from './components/Branding'; export * from './components/ErrorFallback'; export * from './components/LoadingScreen'; export * from './components/Logo'; -export * from './components/Navbar'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f30da1b57..73c18fdf3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -620,18 +620,12 @@ importers: '@open-data-capture/react-core': specifier: workspace:* version: link:../../packages/react-core - '@react-spring/web': - specifier: ^9.7.3 - version: 9.7.3(react-dom@18.2.0)(react@18.2.0) '@tanstack/react-query': specifier: ^5.17.9 version: 5.22.2(react@18.2.0) '@tanstack/react-query-devtools': specifier: ^5.17.9 version: 5.24.0(@tanstack/react-query@5.22.2)(react@18.2.0) - '@use-gesture/react': - specifier: ^10.3.0 - version: 10.3.0(react@18.2.0) axios: specifier: ^1.6.5 version: 1.6.7(debug@4.3.4) @@ -5775,59 +5769,6 @@ packages: '@babel/runtime': 7.23.9 dev: true - /@react-spring/animated@9.7.3(react@18.2.0): - resolution: - { integrity: sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw== } - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@react-spring/shared': 9.7.3(react@18.2.0) - '@react-spring/types': 9.7.3 - react: 18.2.0 - dev: false - - /@react-spring/core@9.7.3(react@18.2.0): - resolution: - { integrity: sha512-IqFdPVf3ZOC1Cx7+M0cXf4odNLxDC+n7IN3MDcVCTIOSBfqEcBebSv+vlY5AhM0zw05PDbjKrNmBpzv/AqpjnQ== } - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@react-spring/animated': 9.7.3(react@18.2.0) - '@react-spring/shared': 9.7.3(react@18.2.0) - '@react-spring/types': 9.7.3 - react: 18.2.0 - dev: false - - /@react-spring/shared@9.7.3(react@18.2.0): - resolution: - { integrity: sha512-NEopD+9S5xYyQ0pGtioacLhL2luflh6HACSSDUZOwLHoxA5eku1UPuqcJqjwSD6luKjjLfiLOspxo43FUHKKSA== } - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@react-spring/types': 9.7.3 - react: 18.2.0 - dev: false - - /@react-spring/types@9.7.3: - resolution: - { integrity: sha512-Kpx/fQ/ZFX31OtlqVEFfgaD1ACzul4NksrvIgYfIFq9JpDHFwQkMVZ10tbo0FU/grje4rcL4EIrjekl3kYwgWw== } - dev: false - - /@react-spring/web@9.7.3(react-dom@18.2.0)(react@18.2.0): - resolution: - { integrity: sha512-BXt6BpS9aJL/QdVqEIX9YoUy8CE6TJrU0mNCqSoxdXlIeNcEBWOfIyE6B14ENNsyQKS3wOWkiJfco0tCr/9tUg== } - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@react-spring/animated': 9.7.3(react@18.2.0) - '@react-spring/core': 9.7.3(react@18.2.0) - '@react-spring/shared': 9.7.3(react@18.2.0) - '@react-spring/types': 9.7.3 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - /@remix-run/router@1.15.1: resolution: { integrity: sha512-zcU0gM3z+3iqj8UX45AmWY810l3oUmXM7uH4dt5xtzvMhRtYVhKGOmgOd1877dOPPepfCjUv57w+syamWIYe7w== } @@ -8082,21 +8023,6 @@ packages: { integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== } dev: true - /@use-gesture/core@10.3.0: - resolution: - { integrity: sha512-rh+6MND31zfHcy9VU3dOZCqGY511lvGcfyJenN4cWZe0u1BH6brBpBddLVXhF2r4BMqWbvxfsbL7D287thJU2A== } - dev: false - - /@use-gesture/react@10.3.0(react@18.2.0): - resolution: - { integrity: sha512-3zc+Ve99z4usVP6l9knYVbVnZgfqhKah7sIG+PS2w+vpig2v2OLct05vs+ZXMzwxdNCMka8B+8WlOo0z6Pn6DA== } - peerDependencies: - react: '>= 16.8.0' - dependencies: - '@use-gesture/core': 10.3.0 - react: 18.2.0 - dev: false - /@vitejs/plugin-react-swc@3.6.0(@swc/helpers@0.5.6)(vite@5.1.4): resolution: { integrity: sha512-XFRbsGgpGxGzEV5i5+vRiro1bwcIaZDIdBRP16qwm+jP68ue/S8FJTBEgOeojtVDYrbSua3XFp71kC8VJE6v+g== }