General application & routing setup, apps menu, links in menus, icons in menus, visual improvements.
This commit is contained in:
parent
97cf06bc7f
commit
3305f09d32
22 changed files with 333 additions and 32 deletions
|
@ -2,7 +2,7 @@ import React, {useState} from "react";
|
|||
import "../index";
|
||||
import {Checkbox} from "../src/Components/Forms/Checkbox";
|
||||
import { Radio } from "../src/Components/Forms/Radio";
|
||||
import {FloppyDisk, TrashSimple, XCircle} from "@phosphor-icons/react";
|
||||
import {AirTrafficControl, Basket, FloppyDisk, House, TrashSimple, XCircle} from "@phosphor-icons/react";
|
||||
import {Card} from "../src/Components/Card";
|
||||
import {PasswordInput} from "../src/Components/Forms/PasswordInput";
|
||||
import {RequiredField} from "../src/Components/Forms/RequiredField";
|
||||
|
@ -18,7 +18,10 @@ import {MainMenu} from "../src/Components/Menus/MainMenu";
|
|||
import {SubmenuFloat} from "../src/Components/Menus/SubmenuFloat";
|
||||
import {Submenu} from "../src/Components/Menus/Submenu";
|
||||
import {SubmenuItem, SubmenuItemSubmenu} from "../src/Components/Menus/SubmenuItem";
|
||||
import {MainMenuItem, MainMenuItemSubmenu} from "../src/Components/Menus/MainMenuItem";
|
||||
import {MainMenuItemSubmenu, MainMenuLink} from "../src/Components/Menus/MainMenuItem";
|
||||
import {AppItem, AppLink, AppsMenu} from "../src/Components/Menus/AppsMenu";
|
||||
import {Application} from "../src/Application/Application";
|
||||
import {Outlet} from "react-router-dom";
|
||||
|
||||
export function DemoApp()
|
||||
{
|
||||
|
@ -27,10 +30,10 @@ export function DemoApp()
|
|||
const [selected, setSelected] = useState(null);
|
||||
|
||||
return (
|
||||
<main className={"app"}>
|
||||
<Application>
|
||||
<MainMenu>
|
||||
<MainMenuItem href={"/"}>Home</MainMenuItem>
|
||||
<MainMenuItem href={"#"}>Test</MainMenuItem>
|
||||
<MainMenuLink to={"/"}><House /> Home</MainMenuLink>
|
||||
<MainMenuLink to={"/test"}><AirTrafficControl /> Test</MainMenuLink>
|
||||
<MainMenuItemSubmenu submenu={
|
||||
<Submenu>
|
||||
<SubmenuItem>Test 1</SubmenuItem>
|
||||
|
@ -44,12 +47,12 @@ export function DemoApp()
|
|||
<SubmenuItem href={"#first-last-choice"}>First last choice</SubmenuItem>
|
||||
<SubmenuItem>Another last choice</SubmenuItem>
|
||||
</Submenu>
|
||||
}>Submenu in submenu</SubmenuItemSubmenu>
|
||||
}><Basket /> Submenu in submenu</SubmenuItemSubmenu>
|
||||
</Submenu>
|
||||
}>Submenu</SubmenuItemSubmenu>
|
||||
}><Basket /> Submenu</SubmenuItemSubmenu>
|
||||
</Submenu>
|
||||
}>
|
||||
Submenu
|
||||
<Basket /> Submenu
|
||||
</MainMenuItemSubmenu>
|
||||
</MainMenu>
|
||||
|
||||
|
@ -58,12 +61,8 @@ export function DemoApp()
|
|||
<h2>TODO</h2>
|
||||
|
||||
<ul>
|
||||
<li>Dropdown menus</li>
|
||||
<li>Main menu</li>
|
||||
<li>Tabs / Apps selectors</li>
|
||||
<li>App steps</li>
|
||||
<li>Pagination</li>
|
||||
<li>Apps</li>
|
||||
<li>Global states</li>
|
||||
<li>Async</li>
|
||||
<li>Subapps</li>
|
||||
|
@ -89,9 +88,9 @@ export function DemoApp()
|
|||
<button type={"button"}>A cool button</button>
|
||||
<a className={"button"} href={"#"}>A link button</a>
|
||||
<button type={"button"} className={"flat"}>A flat button</button>
|
||||
<button type={"button"} className={"validation"}><FloppyDisk weight={"bold"}/> A validation button</button>
|
||||
<button type={"button"} className={"cancel"}><XCircle weight={"bold"}/> A cancellation button</button>
|
||||
<button type={"button"} className={"delete"}><TrashSimple weight={"bold"}/> A deletion button</button>
|
||||
<button type={"button"} className={"validation"}><FloppyDisk /> A validation button</button>
|
||||
<button type={"button"} className={"cancel"}><XCircle /> A cancellation button</button>
|
||||
<button type={"button"} className={"delete"}><TrashSimple /> A deletion button</button>
|
||||
|
||||
<h2>Forms</h2>
|
||||
|
||||
|
@ -303,15 +302,34 @@ export function DemoApp()
|
|||
<SubmenuItemSubmenu submenu={
|
||||
<Submenu>
|
||||
<SubmenuItem>Test A</SubmenuItem>
|
||||
<SubmenuItem>Test B</SubmenuItem>
|
||||
<SubmenuItem><AirTrafficControl /> Test B</SubmenuItem>
|
||||
</Submenu>
|
||||
}>
|
||||
Submenu
|
||||
<Basket /> Submenu
|
||||
</SubmenuItemSubmenu>
|
||||
</Submenu>
|
||||
} floatingOptions={{ placement: "right-start" }}>
|
||||
<button>Submenu on a button</button>
|
||||
</SubmenuFloat>
|
||||
</main>
|
||||
|
||||
<h2>App selectors</h2>
|
||||
|
||||
<AppsMenu>
|
||||
<AppLink to={"/"}>
|
||||
<House />
|
||||
Home
|
||||
</AppLink>
|
||||
<AppLink to={"/test"}>
|
||||
<AirTrafficControl />
|
||||
Test link
|
||||
</AppLink>
|
||||
<AppItem>
|
||||
<Basket />
|
||||
Test 3
|
||||
</AppItem>
|
||||
</AppsMenu>
|
||||
|
||||
<Outlet />
|
||||
</Application>
|
||||
);
|
||||
}
|
||||
|
|
14
demo/NavTest.tsx
Normal file
14
demo/NavTest.tsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import React from "react";
|
||||
import {Card} from "../src/Components/Card";
|
||||
|
||||
/**
|
||||
* Navigation test component.
|
||||
*/
|
||||
export function NavTest()
|
||||
{
|
||||
return (
|
||||
<Card>
|
||||
This is a navigation test.
|
||||
</Card>
|
||||
)
|
||||
}
|
|
@ -1,11 +1,32 @@
|
|||
import React from "react";
|
||||
import {createRoot} from "react-dom/client";
|
||||
import {DemoApp} from "./DemoApp";
|
||||
import {createBrowserRouter} from "react-router-dom";
|
||||
import {Kernel} from "../src/Application/Kernel";
|
||||
import {NavTest} from "./NavTest";
|
||||
|
||||
// Router initialization.
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "/",
|
||||
element: <DemoApp />,
|
||||
children: [
|
||||
{
|
||||
path: "test",
|
||||
element: <NavTest />,
|
||||
}
|
||||
],
|
||||
}
|
||||
])
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const demoApp = document.getElementById("demo-app");
|
||||
|
||||
const root = createRoot(demoApp);
|
||||
|
||||
root.render(<DemoApp />);
|
||||
root.render(<Kernel router={router} footer={
|
||||
<footer>
|
||||
Footer test.
|
||||
</footer>
|
||||
} />);
|
||||
});
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
"@fontsource-variable/source-serif-4": "^5.0.19",
|
||||
"@phosphor-icons/react": "^2.1.5",
|
||||
"react": "^18.3.1",
|
||||
"react-merge-refs": "^2.1.1"
|
||||
"react-merge-refs": "^2.1.1",
|
||||
"react-router-dom": "^6.24.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.3.3",
|
||||
|
|
13
src/Application/Application.tsx
Normal file
13
src/Application/Application.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import React from "react";
|
||||
|
||||
/**
|
||||
* Main Kernel UI application.
|
||||
*/
|
||||
export function Application({children}: React.PropsWithChildren<{}>)
|
||||
{
|
||||
return (
|
||||
<main className={"app"}>
|
||||
{children}
|
||||
</main>
|
||||
);
|
||||
}
|
24
src/Application/Kernel.tsx
Normal file
24
src/Application/Kernel.tsx
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { IconContext } from "@phosphor-icons/react";
|
||||
import React from "react";
|
||||
import {createBrowserRouter, RouterProvider} from "react-router-dom";
|
||||
|
||||
/**
|
||||
* Main Kernel UI app component which initializes everything.
|
||||
*/
|
||||
export function Kernel({header, footer, router}: {
|
||||
header?: React.ReactNode;
|
||||
footer?: React.ReactNode;
|
||||
router: ReturnType<typeof createBrowserRouter>;
|
||||
})
|
||||
{
|
||||
return (
|
||||
<IconContext.Provider value={{
|
||||
size: 16,
|
||||
weight: "bold",
|
||||
}}>
|
||||
{header}
|
||||
<RouterProvider router={router} />
|
||||
{footer}
|
||||
</IconContext.Provider>
|
||||
);
|
||||
}
|
|
@ -46,7 +46,7 @@ export function Datepicker({date, onDateSelected, locale, className, ...divProps
|
|||
onDateSelected(newDate);
|
||||
}, [date, onDateSelected])
|
||||
}>
|
||||
<CaretLeft weight={"bold"}/>
|
||||
<CaretLeft />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip content={nextMonthName}>
|
||||
|
@ -57,7 +57,7 @@ export function Datepicker({date, onDateSelected, locale, className, ...divProps
|
|||
onDateSelected(newDate);
|
||||
}, [date, onDateSelected])
|
||||
}>
|
||||
<CaretRight weight={"bold"}/>
|
||||
<CaretRight />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@ export function Checkbox({children, className, type, ...inputProps}: React.Props
|
|||
return (
|
||||
<label className={classes("box", className)}>
|
||||
<input type={"checkbox"} {...inputProps} />
|
||||
<a className={"button"} tabIndex={-1}><Check weight={"bold"} /></a>
|
||||
<a className={"button"} tabIndex={-1}><Check /></a>
|
||||
{children}
|
||||
</label>
|
||||
);
|
||||
|
|
|
@ -15,7 +15,7 @@ export function PasswordInput({children, className, type, ...props}: React.Props
|
|||
setShowPassword(!showPassword);
|
||||
}}>
|
||||
{
|
||||
showPassword ? <EyeSlash weight={"bold"} /> : <Eye weight={"bold"} />
|
||||
showPassword ? <EyeSlash /> : <Eye />
|
||||
}
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@ export function Radio({children, className, type, ...inputProps}: React.PropsWit
|
|||
return (
|
||||
<label className={classes("box", className)}>
|
||||
<input type={"radio"} {...inputProps} />
|
||||
<a className={"button"} tabIndex={-1}><Check weight={"bold"} /></a>
|
||||
<a className={"button"} tabIndex={-1}><Check /></a>
|
||||
{children}
|
||||
</label>
|
||||
);
|
||||
|
|
54
src/Components/Menus/AppsMenu.tsx
Normal file
54
src/Components/Menus/AppsMenu.tsx
Normal file
|
@ -0,0 +1,54 @@
|
|||
import React from "react";
|
||||
import {classes} from "../../Utils";
|
||||
import {IconContext} from "@phosphor-icons/react";
|
||||
import {NavLink, NavLinkProps} from "react-router-dom";
|
||||
|
||||
/**
|
||||
* Main apps menu component.
|
||||
*/
|
||||
export function AppsMenu({className, children, ...props}: React.HTMLAttributes<HTMLDivElement>)
|
||||
{
|
||||
return (
|
||||
<IconContext.Consumer>
|
||||
{(value) => (
|
||||
<IconContext.Provider value={Object.assign({}, value, {
|
||||
size: 40,
|
||||
})}>
|
||||
<nav className={classes("apps", "menu", className)} {...props}>
|
||||
<ul>
|
||||
{children}
|
||||
</ul>
|
||||
</nav>
|
||||
</IconContext.Provider>
|
||||
)}
|
||||
</IconContext.Consumer>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component of an app item in apps menu.
|
||||
*/
|
||||
export function AppItem({className, children, ...props}: React.HTMLAttributes<HTMLAnchorElement>)
|
||||
{
|
||||
return (
|
||||
<li>
|
||||
<a className={classes("app", "flat button", className)} {...props}>
|
||||
{children}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component of an app link in apps menu.
|
||||
*/
|
||||
export function AppLink({className, children, ...props}: NavLinkProps & React.HTMLAttributes<HTMLAnchorElement>)
|
||||
{
|
||||
return (
|
||||
<li>
|
||||
<NavLink className={classes("app", "flat button", className)} {...props}>
|
||||
{children}
|
||||
</NavLink>
|
||||
</li>
|
||||
);
|
||||
}
|
|
@ -1,7 +1,11 @@
|
|||
import React from "react";
|
||||
import {classes, Modify} from "../../Utils";
|
||||
import {SubmenuFloat} from "./SubmenuFloat";
|
||||
import {NavLink, NavLinkProps} from "react-router-dom";
|
||||
|
||||
/**
|
||||
* Main menu item properties.
|
||||
*/
|
||||
export type MainMenuItemProperties = React.PropsWithChildren<Modify<React.AnchorHTMLAttributes<HTMLAnchorElement>, {
|
||||
}>>;
|
||||
|
||||
|
@ -17,6 +21,24 @@ export const MainMenuItem = React.forwardRef<HTMLAnchorElement, MainMenuItemProp
|
|||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* A main menu item link properties.
|
||||
*/
|
||||
export type MainMenuLinkProperties = React.PropsWithChildren<Modify<NavLinkProps & React.AnchorHTMLAttributes<HTMLAnchorElement>, {
|
||||
}>>;
|
||||
|
||||
/**
|
||||
* A main menu item link.
|
||||
*/
|
||||
export const MainMenuLink = React.forwardRef<HTMLAnchorElement, MainMenuLinkProperties>(function MainMenuLink({children, ...props}: MainMenuLinkProperties, ref)
|
||||
{
|
||||
return (
|
||||
<li>
|
||||
<NavLink ref={ref} {...props}>{children}</NavLink>
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* A main menu item that open a submenu.
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import React from "react";
|
||||
import {classes, Modify} from "../../Utils";
|
||||
import {SubmenuFloat} from "./SubmenuFloat";
|
||||
import {NavLink, NavLinkProps} from "react-router-dom";
|
||||
|
||||
/**
|
||||
* Submenu item properties.
|
||||
*/
|
||||
export type SubmenuItemProperties = React.PropsWithChildren<Modify<React.AnchorHTMLAttributes<HTMLAnchorElement>, {
|
||||
}>>;
|
||||
|
||||
|
@ -15,6 +19,22 @@ export const SubmenuItem = React.forwardRef<HTMLAnchorElement, SubmenuItemProper
|
|||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* A submenu item link properties.
|
||||
*/
|
||||
export type SubmenuLinkProperties = React.PropsWithChildren<Modify<NavLinkProps & React.AnchorHTMLAttributes<HTMLAnchorElement>, {
|
||||
}>>;
|
||||
|
||||
/**
|
||||
* A submenu item link.
|
||||
*/
|
||||
export const SubmenuLink = React.forwardRef<HTMLAnchorElement, SubmenuLinkProperties>(function SubmenuLink({className, children, ...props}: SubmenuLinkProperties, ref)
|
||||
{
|
||||
return (
|
||||
<NavLink ref={ref} className={classes("item", className)} {...props}>{children}</NavLink>
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* A submenu item that open a submenu.
|
||||
*/
|
||||
|
|
|
@ -126,7 +126,7 @@ export function OptionsSuggestions<OptionKey extends keyof any, Option>({options
|
|||
onClick={() => { onSelected(key, option); }}>
|
||||
{(renderOption ?? defaultRenderOption)(option)}
|
||||
|
||||
<span className={"selected"}><Check weight={"bold"} /></span>
|
||||
<span className={"selected"}><Check /></span>
|
||||
</a>
|
||||
));
|
||||
}
|
||||
|
|
|
@ -205,17 +205,17 @@ export function Select<OptionKey extends keyof any, Option>(
|
|||
{...props} />
|
||||
</Suggestible>
|
||||
|
||||
<a className={"button"} tabIndex={-1}><CaretDown weight={"bold"}/></a>
|
||||
<a className={"button"} tabIndex={-1}><CaretDown /></a>
|
||||
</div>
|
||||
|
||||
<ul className={"selected"}>
|
||||
{ // Showing each selected value.
|
||||
selectedOptions.map(([optionKey, option]) => (
|
||||
<li key={String(optionKey)}>
|
||||
<Check weight={"bold"}/>
|
||||
<Check />
|
||||
<div className={"option"}>{(renderOption ?? defaultRenderOption)(option)}</div>
|
||||
<button className={"remove flat"} type={"button"} onClick={() => handleDeselectedOption(optionKey)}>
|
||||
<X weight={"bold"}/>
|
||||
<X />
|
||||
</button>
|
||||
</li>
|
||||
))
|
||||
|
|
|
@ -85,4 +85,5 @@
|
|||
|
||||
|
||||
@menu-hover: rgba(255, 255, 255, 0.15); --menu-hover: @menu-hover;
|
||||
@menu-active: rgba(0, 0, 0, 0.125); --menu-active: @menu-active;
|
||||
}
|
||||
|
|
|
@ -152,13 +152,13 @@ a.button, button, input[type="submit"], input[type="reset"]
|
|||
}
|
||||
|
||||
svg
|
||||
{ // Icon style.*
|
||||
{ // Icon style.
|
||||
display: inline-block;
|
||||
margin-top: -0.2em;
|
||||
margin-right: 0.2em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
> svg:last-of-type
|
||||
&.icon-only svg
|
||||
{
|
||||
margin-right: 0.05em;
|
||||
}
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
@import "menus/_apps-menu";
|
||||
@import "menus/_main-menu";
|
||||
@import "menus/_submenu";
|
||||
|
|
49
src/styles/components/menus/_apps-menu.less
Normal file
49
src/styles/components/menus/_apps-menu.less
Normal file
|
@ -0,0 +1,49 @@
|
|||
nav.apps.menu
|
||||
{
|
||||
> ul
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
gap: 0.66em;
|
||||
|
||||
margin: auto;
|
||||
padding: 0;
|
||||
|
||||
list-style: none;
|
||||
|
||||
> li
|
||||
{
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
a.app
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
margin: auto;
|
||||
padding: 1em;
|
||||
min-width: 10em;
|
||||
|
||||
font-size: 1.1em;
|
||||
|
||||
svg
|
||||
{
|
||||
display: block;
|
||||
margin: 0 auto 0.5em auto;
|
||||
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
&.active
|
||||
{
|
||||
outline: solid 2px var(--primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,13 @@
|
|||
nav.main.menu
|
||||
{
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
||||
background: var(--primary-gradient);
|
||||
color: var(--background);
|
||||
|
||||
z-index: 2;
|
||||
|
||||
.floating
|
||||
{
|
||||
justify-content: flex-start;
|
||||
|
@ -47,6 +52,19 @@ nav.main.menu
|
|||
{
|
||||
background: var(--menu-hover);
|
||||
}
|
||||
|
||||
&.active
|
||||
{
|
||||
background: var(--menu-active);
|
||||
}
|
||||
|
||||
svg
|
||||
{ // Icon style.
|
||||
display: inline-block;
|
||||
margin-top: -0.2em;
|
||||
margin-right: 0.2em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +86,11 @@ nav.main.menu
|
|||
{
|
||||
background: var(--menu-hover);
|
||||
}
|
||||
|
||||
&.active
|
||||
{
|
||||
background: var(--menu-active);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.submenu
|
||||
> .submenu
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -32,6 +32,14 @@
|
|||
{
|
||||
background: var(--background-darker);
|
||||
}
|
||||
|
||||
svg
|
||||
{ // Icon style.
|
||||
display: inline-block;
|
||||
margin-top: -0.2em;
|
||||
margin-right: 0.2em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
32
yarn.lock
32
yarn.lock
|
@ -651,6 +651,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@remix-run/router@npm:1.17.1":
|
||||
version: 1.17.1
|
||||
resolution: "@remix-run/router@npm:1.17.1"
|
||||
checksum: 10c0/bee1631feb03975b64e1c7b574da432a05095dda2ff0f164c737e4952841a58d7b9861de87bd13a977fd970c74dcf8c558fc2d26c6ec01a9ae9041b1b4430869
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/pluginutils@npm:^5.1.0":
|
||||
version: 5.1.0
|
||||
resolution: "@rollup/pluginutils@npm:5.1.0"
|
||||
|
@ -1826,6 +1833,7 @@ __metadata:
|
|||
react: "npm:^18.3.1"
|
||||
react-dom: "npm:^18.3.1"
|
||||
react-merge-refs: "npm:^2.1.1"
|
||||
react-router-dom: "npm:^6.24.1"
|
||||
typescript: "npm:^5.4.5"
|
||||
vite: "npm:^5.2.11"
|
||||
vite-plugin-dts: "npm:^3.9.1"
|
||||
|
@ -2313,6 +2321,30 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-router-dom@npm:^6.24.1":
|
||||
version: 6.24.1
|
||||
resolution: "react-router-dom@npm:6.24.1"
|
||||
dependencies:
|
||||
"@remix-run/router": "npm:1.17.1"
|
||||
react-router: "npm:6.24.1"
|
||||
peerDependencies:
|
||||
react: ">=16.8"
|
||||
react-dom: ">=16.8"
|
||||
checksum: 10c0/458c6c539304984c47b0ad8d5d5b1f8859cc0845e47591d530cb4fcb13498f70a89b42bc4daeea55d57cfa08408b453bcf601cabb2c987f554cdcac13805caa8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-router@npm:6.24.1":
|
||||
version: 6.24.1
|
||||
resolution: "react-router@npm:6.24.1"
|
||||
dependencies:
|
||||
"@remix-run/router": "npm:1.17.1"
|
||||
peerDependencies:
|
||||
react: ">=16.8"
|
||||
checksum: 10c0/f50c78ca52c5154ab933c17708125e8bf71ccf2072993a80302526a0a23db9ceac6e36d5c891d62ccd16f13e60cd1b6533a2036523d1b09e0148ac49e34b2e83
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react@npm:^18.3.1":
|
||||
version: 18.3.1
|
||||
resolution: "react@npm:18.3.1"
|
||||
|
|
Loading…
Reference in a new issue