From 2c35153baaebad4d44e8e9637a97b9ae11be8054 Mon Sep 17 00:00:00 2001 From: Davide Date: Fri, 3 Jan 2025 22:04:04 +0100 Subject: [PATCH] refactor contextmenu and dropdownmenu --- .../src/components/Instance/Tile.tsx | 919 ++++++++++-------- .../modals/Changelogs/changelogs.ts | 46 +- .../modals/InstanceCreation/index.tsx | 19 +- .../mainWindow/src/pages/Library/HomeGrid.tsx | 268 +++-- .../src/pages/Library/Instance/index.tsx | 103 +- .../mainWindow/src/pages/Settings/Java.tsx | 29 +- packages/i18n/locale/english/common.json | 11 +- packages/ui/package.json | 4 + packages/ui/src/Button/index.tsx | 10 +- packages/ui/src/DropdownMenu/index.tsx | 287 ++++++ packages/ui/src/Menu/index.tsx | 404 +++++--- packages/ui/src/index.ts | 5 +- packages/ui/src/util.ts | 7 + pnpm-lock.yaml | 274 +++++- 14 files changed, 1626 insertions(+), 760 deletions(-) create mode 100644 packages/ui/src/DropdownMenu/index.tsx create mode 100644 packages/ui/src/util.ts diff --git a/apps/desktop/packages/mainWindow/src/components/Instance/Tile.tsx b/apps/desktop/packages/mainWindow/src/components/Instance/Tile.tsx index 7022379fe..6c7f4f3f7 100644 --- a/apps/desktop/packages/mainWindow/src/components/Instance/Tile.tsx +++ b/apps/desktop/packages/mainWindow/src/components/Instance/Tile.tsx @@ -8,7 +8,22 @@ import { import { For, Match, Show, Switch, createSignal, mergeProps } from "solid-js" import { Trans, useTransContext } from "@gd/i18n" import { rspc } from "@/utils/rspcClient" -import { ContextMenu, Popover, Spinner, Tooltip } from "@gd/ui" +import { + ContextMenu, + ContextMenuContent, + ContextMenuGroup, + ContextMenuGroupLabel, + ContextMenuItem, + ContextMenuPortal, + ContextMenuSeparator, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuTrigger, + Popover, + Spinner, + Tooltip +} from "@gd/ui" import DefaultImg from "/assets/images/default-instance-img.png" import { useGDNavigate } from "@/managers/NavigationManager" import { useModal } from "@/managers/ModalsManager" @@ -85,6 +100,10 @@ const Tile = (props: Props) => { }) } + const setFavoriteMutation = rspc.createMutation(() => ({ + mutationKey: ["instance.setFavorite"] + })) + const isLoading = () => props.isLoading const handlePlay = () => { @@ -171,71 +190,6 @@ const Tile = (props: Props) => { } } - const menuItems = () => [ - { - icon: props.isRunning ? "i-ri:stop-fill" : "i-ri:play-fill", - label: props.isRunning ? t("instance.stop") : t("instance.action_play"), - action: handlePlay, - disabled: isLoading() || isInQueue() || props.isDeleting - }, - { - icon: "i-ri:pencil-fill", - label: t("instance.action_edit"), - action: handleEdit, - disabled: isLoading() || isInQueue() || props.isDeleting - }, - { - icon: "i-ri:settings-3-fill", - label: t("instance.action_settings"), - action: handleSettings, - disabled: isLoading() || isInQueue() || props.isDeleting - }, - ...(!props.isInvalid - ? [ - { - icon: "i-ri:file-copy-fill", - label: t("instance.action_duplicate"), - action: handleDuplicate, - disabled: isLoading() || isInQueue() || props.isDeleting - } - ] - : []), - { - icon: "i-ri:folder-open-fill", - label: t("instance.action_open_folder"), - action: handleOpenFolder - }, - { - icon: "i-mingcute:file-export-fill", - label: t("instance.export_instance"), - action: () => { - const instanceId = props.instance.id - setInstanceId(instanceId) - setPayload({ - target: "Curseforge", - save_path: undefined, - self_contained_addons_bundling: false, - filter: { entries: {} }, - - instance_id: instanceId - }) - setExportStep(0) - setCheckedFiles([]) - modalsContext?.openModal({ - name: "exportInstance" - }) - }, - disabled: isLoading() || isInQueue() || props.isDeleting - }, - { - id: "delete", - icon: "i-ri:delete-bin-2-fill", - label: t("instance.action_delete"), - action: handleDelete, - disabled: isLoading() || isInQueue() || props.isDeleting - } - ] - const getTranslationArgs = (translation: Translation) => { if ("args" in translation) { return translation.args @@ -248,391 +202,532 @@ const Tile = (props: Props) => { return ( - - - props.failError ? ( -
-
-
- -
-
- -
{ - navigator.clipboard.writeText(props.failError!) - - setCopiedError(true) - - setTimeout(() => { - setCopiedError(false) - }, 2000) - }} - /> - -
-
-
{props.failError}
-
- ) : undefined - } - > -
{ - e.stopPropagation() - if ( - !isLoading() && - !isInQueue() && - !props.isInvalid && - !props.isDeleting - ) { - props?.onClick?.(e) - } - }} - > -
+ + + + + {props.instance.name} + + +
+ {props.isRunning + ? t("instance.stop") + : t("instance.action_play")} + + +
+ {t("instance.action_edit")} + + +
+ {t("instance.action_settings")} + + { + setFavoriteMutation.mutate({ + instance: props.instance.id, + favorite: !props.instance.favorite + }) + }} + >
+ {props.instance.favorite + ? t("instance.remove_favorite") + : t("instance.add_favorite")} + + { + const instanceId = props.instance.id + setInstanceId(instanceId) + setPayload({ + target: "Curseforge", + save_path: undefined, + self_contained_addons_bundling: false, + filter: { entries: {} }, + instance_id: instanceId + }) + setExportStep(0) + setCheckedFiles([]) + modalsContext?.openModal({ + name: "exportInstance" + }) + }} + disabled={isLoading() || isInQueue() || props.isDeleting} + > +
+ {t("instance.export_instance")} + + + + + {t("instance.more_options")} + + + + +
+ {t("instance.action_open_folder")} + + { + navigate(`/library/${props.instance.id}/logs`) + }} + > +
+ {t("instance.view_logs")} + + { + navigate(`/library/${props.instance.id}/mods`) + }} + > +
+ {t("instance.view_mods")} + + {!props.isInvalid && ( + +
+ {t("instance.action_duplicate")} + + )} + + + + + +
+ {t("instance.action_delete")} + + + + + + props.failError ? ( +
+
+
+ +
+
+ +
{ + navigator.clipboard.writeText(props.failError!) + + setCopiedError(true) + + setTimeout(() => { + setCopiedError(false) + }, 2000) + }} + /> + +
+
+
{props.failError}
+
+ ) : undefined + } + > +
{ + e.stopPropagation() + if ( + !isLoading() && + !isInQueue() && + !props.isInvalid && + !props.isDeleting + ) { + props?.onClick?.(e) } - > + }} + > +
- -

- -

-
-
-
- - -
-
-
-
-
- -
-
- () -
-
- - - -
-

- {Math.round(props.percentage!)}% -

-
- - {(subTask) => ( -
1, - "text-md": props.subTasks?.length === 1 - }} - > - -
- )} -
-
-
-
- -
- - - - - - - - - -
-
- -
- -
-
- -
-
-
- -
+ +

+ +

+
+
+
+ + +
+
+
+
+
+ +
+
+ () +
+
+ -

- 20 ? props.instance.name : "" - } - placement="top" - class="w-full text-ellipsis overflow-hidden" - > - {props.instance.name} - -

- - -
- +
+

+ {Math.round(props.percentage!)}% +

+
+ + {(subTask) => ( +
1, + "text-md": props.subTasks?.length === 1 + }} + > + +
+ )} +
+
+
+ + +
+ + + + + + + + + +
+
+ +
+ +
+
+ +
+
+
+ + - - + +

-

- {Math.round(props.downloaded || 0)}MB/ - {Math.round(props.totalDownload || 0)}MB -

- - -

- + 20 ? props.instance.name : "" + } + placement="top" + class="w-full overflow-hidden text-ellipsis" + > + {props.instance.name} + + + + +
+ + + + + +

{props.version}

+
+
+ +

+ {Math.round(props.downloaded || 0)}MB/ + {Math.round(props.totalDownload || 0)}MB +

+
+
+
+ + diff --git a/apps/desktop/packages/mainWindow/src/managers/ModalsManager/modals/Changelogs/changelogs.ts b/apps/desktop/packages/mainWindow/src/managers/ModalsManager/modals/Changelogs/changelogs.ts index 8cec8e1eb..d3a191482 100644 --- a/apps/desktop/packages/mainWindow/src/managers/ModalsManager/modals/Changelogs/changelogs.ts +++ b/apps/desktop/packages/mainWindow/src/managers/ModalsManager/modals/Changelogs/changelogs.ts @@ -38,12 +38,17 @@ const changelogs: Changelog = { "The old one was more of a placeholder. This page is still under heavy development, but it's already a lot better than the old one." }, { - title: "Library featured modpack can now be hidden", - description: "by clicking the eye icon in the top right corner." + title: "Library featured modpack can now be hidden.", + description: "By clicking the eye icon in the top right corner." }, { title: - "Added confirmation dialog when trying to launch an instance with a expired or invalid account." + "Added confirmation dialog when trying to launch an instance with an expired or invalid account." + }, + { + title: 'Added "Add new instance" context menu to instances page', + description: + "You can access it by right-clicking in any blank space in the instances page." } ], fixed: [ @@ -51,7 +56,7 @@ const changelogs: Changelog = { title: "Fixed instances crashing when having names with precomposed UNICODE characters.", description: - "You can now use any character in instance names, including japanese characters, emoji, and any other unicode characters." + "You can now use any character in instance names, including Japanese characters, emoji, and any other Unicode characters." }, { title: @@ -63,14 +68,19 @@ const changelogs: Changelog = { }, { title: - "Fixed Minecraft 1.21.2+ not working with fabric and other modloaders" + "Fixed Minecraft 1.21.2+ not working with fabric and other modloaders." }, { - title: "Fixed tabs always being flagged as selected by default" + title: "Fixed tabs always being flagged as selected by default." }, { title: - "Fixed infinite calls sometimes being made to the API from the instance page resulting in errors" + "Fixed infinite calls sometimes being made to the API from the instance page resulting in errors." + }, + { + title: "Fixed the modpack updater.", + description: + "While the overall logic should now be more stable, it is still being worked on and may still have some bugs." } ], improved: [ @@ -80,7 +90,7 @@ const changelogs: Changelog = { { title: "Updated dependencies & toolchain.", description: - "This basically means more stability and performance, as well as less bugs and security issues." + "This basically means more stability and performance, as well as fewer bugs and security issues." }, { title: "Added a small transition when switching between pages." @@ -90,16 +100,16 @@ const changelogs: Changelog = { "Internal technical change that should improve performance across pages in some cases." }, { - title: "Added many micro-transitions", - description: "to various parts of the app, like the instances page." + title: "Added many micro-transitions.", + description: "To various parts of the app, like the instances page." }, { title: "Redesigned news component.", description: - "It now takes up less space, and accomodates for a smaller featured tile. While it's static for now, we're working on a dynamic featured tile." + "It now takes up less space, and accommodates for a smaller featured tile. While it's static for now, we're working on a dynamic featured tile." }, { - title: "Improved network download performance", + title: "Improved network download performance.", description: "We've made some changes to the way we download files, which should improve performance and, more importantly, make them more reliable." }, @@ -112,14 +122,18 @@ const changelogs: Changelog = { title: "Potato PC mode now also disables hardware acceleration." }, { - title: "Fully reworked how consents are handled", - description: "resulting in a deeper compliance with GDPR and CCPA." + title: "Fully reworked how consents are handled.", + description: "Resulting in a deeper compliance with GDPR and CCPA." + }, + { + title: "Updated terms of service and privacy statement." }, { - title: "Updated terms of service and privacy statement" + title: "Added a parallax effect to the instance cover image." }, { - title: "Added a parallax effect to the instance cover image" + title: "Reworked context menus and dropdown menus", + description: "now being more accessible and easier to use." } ] } diff --git a/apps/desktop/packages/mainWindow/src/managers/ModalsManager/modals/InstanceCreation/index.tsx b/apps/desktop/packages/mainWindow/src/managers/ModalsManager/modals/InstanceCreation/index.tsx index 63d105b63..1c541f73a 100644 --- a/apps/desktop/packages/mainWindow/src/managers/ModalsManager/modals/InstanceCreation/index.tsx +++ b/apps/desktop/packages/mainWindow/src/managers/ModalsManager/modals/InstanceCreation/index.tsx @@ -1,31 +1,34 @@ import { Tab, TabList, TabPanel, Tabs } from "@gd/ui" import { ModalProps } from "../.." import ModalLayout from "../../ModalLayout" -import { Trans } from "@gd/i18n" +import { Trans, useTransContext } from "@gd/i18n" import Custom from "./Custom" import Import from "./Import" import { Match, Switch } from "solid-js" interface Props { id?: number + import?: boolean } const InstanceCreation = (props: ModalProps) => { const data: () => Props = () => props.data + const [t] = useTransContext() + + const title = () => + data()?.id !== undefined && data()?.id !== null + ? t("modals.title.modify_instance") + : t("modals.title.new_instance") return ( - -
+ +
- + diff --git a/apps/desktop/packages/mainWindow/src/pages/Library/HomeGrid.tsx b/apps/desktop/packages/mainWindow/src/pages/Library/HomeGrid.tsx index 0b370e960..e347e582e 100644 --- a/apps/desktop/packages/mainWindow/src/pages/Library/HomeGrid.tsx +++ b/apps/desktop/packages/mainWindow/src/pages/Library/HomeGrid.tsx @@ -1,6 +1,13 @@ import { Button, Collapsable, + ContextMenu, + ContextMenuContent, + ContextMenuGroup, + ContextMenuGroupLabel, + ContextMenuItem, + ContextMenuSeparator, + ContextMenuTrigger, Dropdown, Input, News, @@ -35,6 +42,7 @@ import { initNews } from "@/utils/news" import { rspc } from "@/utils/rspcClient" import { createStore, reconcile } from "solid-js/store" import { useGlobalStore } from "@/components/GlobalStoreContext" +import { useModal } from "@/managers/ModalsManager" const NewsWrapper = () => { const newsInitializer = initNews() @@ -73,6 +81,8 @@ const HomeGrid = () => { const globalStore = useGlobalStore() + const modals = useModal() + const [instancesTileSize, setInstancesTileSize] = createSignal(2) const [instances, setInstances] = createStore< @@ -343,9 +353,9 @@ const HomeGrid = () => { !globalStore.instances.isLoading } > -
- -

+

+ +

@@ -357,7 +367,7 @@ const HomeGrid = () => { } >
-
+
{ noTip noPadding content={() => ( -
-
+
+
-
+
@@ -423,7 +433,7 @@ const HomeGrid = () => { />
-
+
@@ -442,7 +452,7 @@ const HomeGrid = () => { }} />
{ />
-
+
@@ -479,7 +489,7 @@ const HomeGrid = () => { }} />
{ )} >
-
- - {(group, i) => { - return ( - 0}> - - {/* + +
+ + {(group, i) => { + return ( + 0}> + + {/* */} - {group.name} - - } - size="standard" - > -
- - {(instance, j) => { - let ref: HTMLDivElement | undefined - - const instancesCountInPreviousGroups = instances - .slice(0, i()) - .reduce( - (acc, group) => acc + group.instances.length, - 0 - ) - - const baseDelay = 300 - - const groupDelay = - i() * 60 + 60 * instancesCountInPreviousGroups - - const instanceDelay = j() * 60 - - const totalDelay = - baseDelay + groupDelay + instanceDelay - - onMount(() => { - if (ref && !initAnimationRan) { - ref.animate( - [ - { - opacity: 0 - }, - { - opacity: 1 - } - ], - { - duration: 250, - delay: totalDelay, - easing: "linear", - fill: "forwards" + {group.name} + + } + size="standard" + > +
+ + {(instance, j) => { + let ref: HTMLDivElement | undefined + + const instancesCountInPreviousGroups = + instances + .slice(0, i()) + .reduce( + (acc, group) => + acc + group.instances.length, + 0 + ) + + const baseDelay = 300 + + const groupDelay = + i() * 60 + + 60 * instancesCountInPreviousGroups + + const instanceDelay = j() * 60 + + const totalDelay = + baseDelay + groupDelay + instanceDelay + + onMount(() => { + if (ref && !initAnimationRan) { + ref.animate( + [ + { + opacity: 0 + }, + { + opacity: 1 + } + ], + { + duration: 250, + delay: totalDelay, + easing: "linear", + fill: "forwards" + } + ) + } + + if ( + i() === instances.length - 1 && + j() === group.instances.length - 1 + ) { + requestAnimationFrame(() => { + initAnimationRan = true + }) } - ) - } - - if ( - i() === instances.length - 1 && - j() === group.instances.length - 1 - ) { - requestAnimationFrame(() => { - initAnimationRan = true }) - } - }) - - return ( -
- -
- ) - }} -
-
- - - ) - }} -
-
+ + return ( +
+ +
+ ) + }} +
+
+
+
+ ) + }} +
+
+ + + + + Add New Instance + + + { + modals?.openModal({ + name: "instanceCreation" + }) + }} + > +
+ Create New Instance + + { + modals?.openModal( + { + name: "instanceCreation" + }, + { + import: true + } + ) + }} + > +
+ Import Instance + + + +
diff --git a/apps/desktop/packages/mainWindow/src/pages/Library/Instance/index.tsx b/apps/desktop/packages/mainWindow/src/pages/Library/Instance/index.tsx index 4d23b402d..64bd498c6 100644 --- a/apps/desktop/packages/mainWindow/src/pages/Library/Instance/index.tsx +++ b/apps/desktop/packages/mainWindow/src/pages/Library/Instance/index.tsx @@ -1,6 +1,15 @@ import getRouteIndex from "@/route/getRouteIndex" import { Trans, useTransContext } from "@gd/i18n" -import { Tabs, TabList, Tab, Button, ContextMenu } from "@gd/ui" +import { + Tabs, + TabList, + Tab, + Button, + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem +} from "@gd/ui" import { Outlet, useLocation, useParams, useRouteData } from "@solidjs/router" import { For, @@ -199,7 +208,7 @@ const Instance = () => { }, { label: ( -
+
Logs
@@ -389,7 +398,7 @@ const Instance = () => { return (
{ ref={(el) => { headerRef = el }} - class="relative flex flex-col justify-between ease-in-out transition-all items-stretch min-h-60 transition-100 overflow-hidden" + class="transition-100 relative flex min-h-60 flex-col items-stretch justify-between overflow-hidden transition-all ease-in-out" > { : DefaultImg } alt="Instance cover" - class="absolute w-full h-full object-cover" + class="absolute h-full w-full object-cover" style={{ transform: `translate3d(0, ${scrollTop() * 0.4}px, 0)`, "will-change": "transform" }} /> -
-
+
+
-
- - - +
+ + + + + + + {(item) => ( + +
+
+ {item.label} +
+ + )} + + +
-
+
-
-
+
+
{ }} /> -
+
{ !editableName() }} > - +

{ setNewName(e.target.innerHTML) }} - class="z-10 m-0 border-box focus-visible:border-0 focus:outline-none focus-visible:outline-none cursor-text min-h-10" + class="border-box z-10 m-0 min-h-10 cursor-text focus:outline-none focus-visible:border-0 focus-visible:outline-none" contentEditable={editableName()} onFocusIn={() => { setEditableName(true) @@ -511,24 +540,24 @@ const Instance = () => {

setEditableName(true)} />
handleNameChange()} />
{
-
+
{ <> Modloader icon @@ -582,7 +611,7 @@ const Instance = () => { undefined } > -
+
{convertSecondsToHumanTime( @@ -597,7 +626,7 @@ const Instance = () => { isModrinth={!!modrinthData()} />
-
+
{
{
- - - + + + + + + + {(item) => ( + +
+ + {item.label} +
+
+ )} +
+
+
diff --git a/packages/i18n/locale/english/common.json b/packages/i18n/locale/english/common.json index 5ff4c5ad7..daa62a9e5 100644 --- a/packages/i18n/locale/english/common.json +++ b/packages/i18n/locale/english/common.json @@ -243,6 +243,12 @@ "instance.action_edit": "Edit", "instance.select_image": "Select image", "instance.action_duplicate": "Duplicate", + "instance.toggle_favorite": "Toggle favorite", + "instance.view_logs": "View logs", + "instance.view_mods": "View mods", + "instance.more_options": "More options", + "instance.add_favorite": "Add favorite", + "instance.remove_favorite": "Remove favorite", "instance.import_select_all_instances": "Select All", "instance.import_deselect_all_instances": "Deselect All", "instance.error_invalid": "Instance Invalid or corrupted, try repairing it!", @@ -515,5 +521,8 @@ "columns.source_kind": "Source Kind", "columns.thread_name": "Thread Name", "columns.level": "Log Level", - "font_size": "Font Size" + "font_size": "Font Size", + + "modals.title.new_instance": "New Instance", + "modals.title.modify_instance": "Modify Instance" } diff --git a/packages/ui/package.json b/packages/ui/package.json index 454e66fa2..afb6ac383 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -21,6 +21,7 @@ "@babel/core": "^7.22.5", "@floating-ui/dom": "^1.4.1", "@gd/config": "workspace:*", + "@kobalte/core": "^0.13.7", "@storybook/addon-essentials": "^7.0.22", "@storybook/addon-interactions": "^7.0.22", "@storybook/addon-links": "^7.0.22", @@ -30,6 +31,7 @@ "@testing-library/jest-dom": "^5.16.5", "babel-loader": "^9.1.2", "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", "concurrently": "^9.1.0", "jsdom": "^25.0.1", "solid-floating-ui": "^0.3.1", @@ -38,6 +40,8 @@ "storybook": "^7.0.22", "storybook-solidjs": "^1.0.0-beta.2", "storybook-solidjs-vite": "^1.0.0-beta.2", + "tailwind-merge": "^2.2.0", + "tailwindcss-animate": "^1.0.7", "unocss": "^0.65.1", "vite": "^6.0.3", "vite-plugin-dts": "^4.3.0", diff --git a/packages/ui/src/Button/index.tsx b/packages/ui/src/Button/index.tsx index 261aef3e0..ff58a0250 100644 --- a/packages/ui/src/Button/index.tsx +++ b/packages/ui/src/Button/index.tsx @@ -8,6 +8,7 @@ import { Match } from "solid-js" import { Spinner } from "../Spinner" +import { Dynamic } from "solid-js/web" type Size = "small" | "medium" | "large" type Type = @@ -20,6 +21,7 @@ type Type = interface Props extends Omit, "type"> { + as?: "button" | "a" | "span" | "div" children: HTMLElement | string | JSX.Element style?: JSX.CSSProperties textColor?: string @@ -191,6 +193,7 @@ function Button(props: Props) { const c = children(() => props.children) const [_, others] = splitProps(props, [ + "as", "icon", "iconRight", "uppercase", @@ -210,8 +213,11 @@ function Button(props: Props) { props ) + const component = props.as || "button" + return ( - + ) } diff --git a/packages/ui/src/DropdownMenu/index.tsx b/packages/ui/src/DropdownMenu/index.tsx new file mode 100644 index 000000000..f70649f3b --- /dev/null +++ b/packages/ui/src/DropdownMenu/index.tsx @@ -0,0 +1,287 @@ +import type { Component, ComponentProps, JSX, ValidComponent } from "solid-js" +import { splitProps } from "solid-js" + +import * as DropdownMenuPrimitive from "@kobalte/core/dropdown-menu" +import type { PolymorphicProps } from "@kobalte/core/polymorphic" + +// import { cn } from "../util" + +const cn = (...args: any[]) => args.join(" ") + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger +const DropdownMenuPortal = DropdownMenuPrimitive.Portal +const DropdownMenuSub = DropdownMenuPrimitive.Sub +const DropdownMenuGroup = DropdownMenuPrimitive.Group +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup + +const DropdownMenu: Component = ( + props +) => { + return +} + +type DropdownMenuContentProps = + DropdownMenuPrimitive.DropdownMenuContentProps & { + class?: string | undefined + } + +const DropdownMenuContent = ( + props: PolymorphicProps> +) => { + const [, rest] = splitProps(props as DropdownMenuContentProps, ["class"]) + return ( + + + + ) +} + +type DropdownMenuItemProps = + DropdownMenuPrimitive.DropdownMenuItemProps & { + class?: string | undefined + } + +const DropdownMenuItem = ( + props: PolymorphicProps> +) => { + const [, rest] = splitProps(props as DropdownMenuItemProps, ["class"]) + return ( + + ) +} + +const DropdownMenuShortcut: Component> = (props) => { + const [, rest] = splitProps(props, ["class"]) + return ( + + ) +} + +const DropdownMenuLabel: Component< + ComponentProps<"div"> & { inset?: boolean } +> = (props) => { + const [, rest] = splitProps(props, ["class", "inset"]) + return ( +
+ ) +} + +type DropdownMenuSeparatorProps = + DropdownMenuPrimitive.DropdownMenuSeparatorProps & { + class?: string | undefined + } + +const DropdownMenuSeparator = ( + props: PolymorphicProps> +) => { + const [, rest] = splitProps(props as DropdownMenuSeparatorProps, ["class"]) + return ( + + ) +} + +type DropdownMenuSubTriggerProps = + DropdownMenuPrimitive.DropdownMenuSubTriggerProps & { + class?: string | undefined + children?: JSX.Element + } + +const DropdownMenuSubTrigger = ( + props: PolymorphicProps> +) => { + const [, rest] = splitProps(props as DropdownMenuSubTriggerProps, [ + "class", + "children" + ]) + return ( + + {props.children} + + + + + ) +} + +type DropdownMenuSubContentProps = + DropdownMenuPrimitive.DropdownMenuSubContentProps & { + class?: string | undefined + } + +const DropdownMenuSubContent = ( + props: PolymorphicProps> +) => { + const [, rest] = splitProps(props as DropdownMenuSubContentProps, ["class"]) + return ( + + ) +} + +type DropdownMenuCheckboxItemProps = + DropdownMenuPrimitive.DropdownMenuCheckboxItemProps & { + class?: string | undefined + children?: JSX.Element + } + +const DropdownMenuCheckboxItem = ( + props: PolymorphicProps> +) => { + const [, rest] = splitProps(props as DropdownMenuCheckboxItemProps, [ + "class", + "children" + ]) + return ( + + + + + + + + + {props.children} + + ) +} + +type DropdownMenuGroupLabelProps = + DropdownMenuPrimitive.DropdownMenuGroupLabelProps & { + class?: string | undefined + } + +const DropdownMenuGroupLabel = ( + props: PolymorphicProps> +) => { + const [, rest] = splitProps(props as DropdownMenuGroupLabelProps, ["class"]) + return ( + + ) +} + +type DropdownMenuRadioItemProps = + DropdownMenuPrimitive.DropdownMenuRadioItemProps & { + class?: string | undefined + children?: JSX.Element + } + +const DropdownMenuRadioItem = ( + props: PolymorphicProps> +) => { + const [, rest] = splitProps(props as DropdownMenuRadioItemProps, [ + "class", + "children" + ]) + return ( + + + + + + + + + {props.children} + + ) +} + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuPortal, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuShortcut, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, + DropdownMenuCheckboxItem, + DropdownMenuGroup, + DropdownMenuGroupLabel, + DropdownMenuRadioGroup, + DropdownMenuRadioItem +} diff --git a/packages/ui/src/Menu/index.tsx b/packages/ui/src/Menu/index.tsx index ca626b561..787f2b6f4 100644 --- a/packages/ui/src/Menu/index.tsx +++ b/packages/ui/src/Menu/index.tsx @@ -1,160 +1,278 @@ -import { - For, - createSignal, - JSX, - onMount, - Show, - mergeProps, - onCleanup -} from "solid-js" -import { Portal } from "solid-js/web" -import { useContextMenu } from "./ContextMenuContext" - -interface MenuItem { - icon?: string - label: string - action: () => void - id?: string - disabled?: boolean +import type { Component, ComponentProps, JSX, ValidComponent } from "solid-js" +import { splitProps } from "solid-js" + +import * as ContextMenuPrimitive from "@kobalte/core/context-menu" +import type { PolymorphicProps } from "@kobalte/core/polymorphic" + +// import { cn } from "../util" + +const cn = (...args: any[]) => args.join(" ") + +const ContextMenuTrigger = ContextMenuPrimitive.Trigger +const ContextMenuPortal = ContextMenuPrimitive.Portal +const ContextMenuSub = ContextMenuPrimitive.Sub +const ContextMenuGroup = ContextMenuPrimitive.Group +const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup + +const ContextMenu: Component = ( + props +) => { + return } -interface ContextMenuProps { - menuItems: MenuItem[] - children: JSX.Element - trigger?: "context" | "click" +type ContextMenuContentProps = + ContextMenuPrimitive.ContextMenuContentProps & { + class?: string | undefined + } + +const ContextMenuContent = ( + props: PolymorphicProps> +) => { + const [local, others] = splitProps(props as ContextMenuContentProps, [ + "class" + ]) + return ( + + + + ) } -const ContextMenu = (props: ContextMenuProps) => { - const [x, setX] = createSignal(0) - const [y, setY] = createSignal(0) - const [menuRef, setMenuRef] = createSignal() - const [containerRef, setContainerRef] = createSignal< - HTMLDivElement | undefined - >() - - const ContextMenu = useContextMenu() - - const mergedProps = mergeProps( - { - trigger: "context" - }, - props +type ContextMenuItemProps = + ContextMenuPrimitive.ContextMenuItemProps & { + class?: string | undefined + } + +const ContextMenuItem = ( + props: PolymorphicProps> +) => { + const [local, others] = splitProps(props as ContextMenuItemProps, ["class"]) + return ( + ) +} + +const ContextMenuShortcut: Component> = (props) => { + const [local, others] = splitProps(props, ["class"]) + return ( + + ) +} - const openContextMenu = (e: MouseEvent) => { - e.preventDefault() - if (containerRef()) { - ContextMenu?.setOpenMenu(containerRef()!) - } - - // Initially set the position to cursor location - setX(e.clientX) - setY(e.clientY) - - // Wait for the next frame when the menu has been painted - requestAnimationFrame(() => { - if (menuRef()) { - const menuElement = menuRef()! - const boundingClientRect = menuElement.getBoundingClientRect() - - const newX = e.clientX // No change to X coordinate - let newY = e.clientY - boundingClientRect.height - - // If the new y position is less than 0, set it to 0 to prevent the menu from going out of view to the top - if (newY < 0) { - newY = 0 - } - - setX(newX) - setY(newY) - } - }) +type ContextMenuSeparatorProps = + ContextMenuPrimitive.ContextMenuSeparatorProps & { + class?: string | undefined } - const closeContextMenu = () => { - ContextMenu?.closeMenu() +const ContextMenuSeparator = ( + props: PolymorphicProps> +) => { + const [local, others] = splitProps(props as ContextMenuSeparatorProps, [ + "class" + ]) + return ( + + ) +} + +type ContextMenuSubTriggerProps = + ContextMenuPrimitive.ContextMenuSubTriggerProps & { + class?: string | undefined + children?: JSX.Element } - // const handleClickOutside = (e: MouseEvent) => { - // if (containerRef() && !containerRef()?.contains(e.target as Node)) { - // closeContextMenu(); - // } - // }; - - const handleClickOutside = (e: MouseEvent) => { - if ( - containerRef() && - !containerRef()?.contains(e.target as Node) && - containerRef() == ContextMenu?.openMenu() - ) { - closeContextMenu() - } +const ContextMenuSubTrigger = ( + props: PolymorphicProps> +) => { + const [local, others] = splitProps(props as ContextMenuSubTriggerProps, [ + "class", + "children" + ]) + return ( + + {local.children} + + + + + ) +} + +type ContextMenuSubContentProps = + ContextMenuPrimitive.ContextMenuSubContentProps & { + class?: string | undefined + } + +const ContextMenuSubContent = ( + props: PolymorphicProps> +) => { + const [local, others] = splitProps(props as ContextMenuSubContentProps, [ + "class" + ]) + return ( + + ) +} + +type ContextMenuCheckboxItemProps = + ContextMenuPrimitive.ContextMenuCheckboxItemProps & { + class?: string | undefined + children?: JSX.Element + } + +const ContextMenuCheckboxItem = ( + props: PolymorphicProps> +) => { + const [local, others] = splitProps(props as ContextMenuCheckboxItemProps, [ + "class", + "children" + ]) + return ( + + + + + + + + + {local.children} + + ) +} + +type ContextMenuGroupLabelProps = + ContextMenuPrimitive.ContextMenuGroupLabelProps & { + class?: string | undefined } - const isContextTrigger = () => mergedProps.trigger === "context" - - onMount(() => { - document.addEventListener("click", handleClickOutside) - if (isContextTrigger()) { - containerRef()?.addEventListener("contextmenu", openContextMenu) - } else { - containerRef()?.addEventListener("click", openContextMenu) - } - }) - - onCleanup(() => { - document.removeEventListener("click", handleClickOutside) - containerRef()?.removeEventListener("contextmenu", openContextMenu) - containerRef()?.removeEventListener("click", openContextMenu) - }) +const ContextMenuGroupLabel = ( + props: PolymorphicProps> +) => { + const [local, others] = splitProps(props as ContextMenuGroupLabelProps, [ + "class" + ]) return ( -
- {props.children} - - -
- - - - -
+ ) +} + +type ContextMenuRadioItemProps = + ContextMenuPrimitive.ContextMenuRadioItemProps & { + class?: string | undefined + children?: JSX.Element + } + +const ContextMenuRadioItem = ( + props: PolymorphicProps> +) => { + const [local, others] = splitProps(props as ContextMenuRadioItemProps, [ + "class", + "children" + ]) + return ( + + + + - - {(item) => ( -
- -
- - {item.label} -
- )} - -
- - -
+ + + + + {local.children} + ) } -export { ContextMenu } +export { + ContextMenu, + ContextMenuTrigger, + ContextMenuPortal, + ContextMenuContent, + ContextMenuItem, + ContextMenuShortcut, + ContextMenuSeparator, + ContextMenuSub, + ContextMenuSubTrigger, + ContextMenuSubContent, + ContextMenuCheckboxItem, + ContextMenuGroup, + ContextMenuGroupLabel, + ContextMenuRadioGroup, + ContextMenuRadioItem +} diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 3f6e43555..7508d69ae 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -1,3 +1,7 @@ +// New components +export * from "./DropdownMenu" +export * from "./Menu" + export { Button } from "./Button" export { Input } from "./Input" export { Select } from "./Select" @@ -23,6 +27,5 @@ export { export { Dropdown } from "./Dropdown" export { Tooltip } from "./Tooltip" export { Popover } from "./Popover" -export { ContextMenu } from "./Menu" export { ContextMenuProvider, useContextMenu } from "./Menu/ContextMenuContext" export * from "./themes" diff --git a/packages/ui/src/util.ts b/packages/ui/src/util.ts new file mode 100644 index 000000000..c66a9d9cc --- /dev/null +++ b/packages/ui/src/util.ts @@ -0,0 +1,7 @@ +import type { ClassValue } from "clsx" +import { clsx } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f4b31e617..5432cfa7d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -333,6 +333,9 @@ importers: '@gd/config': specifier: workspace:* version: link:../config + '@kobalte/core': + specifier: ^0.13.7 + version: 0.13.7(solid-js@1.9.3) '@storybook/addon-essentials': specifier: ^7.0.22 version: 7.6.10(@types/react@18.2.48)(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -344,7 +347,7 @@ importers: version: 7.6.10(react@18.2.0) '@storybook/addon-styling': specifier: ^1.3.0 - version: 1.3.7(@types/react@18.2.48)(encoding@0.1.13)(less@4.2.0)(postcss@8.4.49)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.6.3)(webpack@5.90.0(esbuild@0.18.20)) + version: 1.3.7(@types/react@18.2.48)(encoding@0.1.13)(less@4.2.0)(postcss@8.4.49)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.6.3)(webpack@5.90.0(esbuild@0.23.1)) '@storybook/blocks': specifier: ^7.0.22 version: 7.6.10(@types/react@18.2.48)(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -356,10 +359,13 @@ importers: version: 5.17.0 babel-loader: specifier: ^9.1.2 - version: 9.1.3(@babel/core@7.23.7)(webpack@5.90.0(esbuild@0.18.20)) + version: 9.1.3(@babel/core@7.23.7)(webpack@5.90.0(esbuild@0.23.1)) class-variance-authority: specifier: ^0.7.0 version: 0.7.0 + clsx: + specifier: ^2.1.1 + version: 2.1.1 concurrently: specifier: ^9.1.0 version: 9.1.0 @@ -384,6 +390,12 @@ importers: storybook-solidjs-vite: specifier: ^1.0.0-beta.2 version: 1.0.0-beta.2(storybook@7.6.10(encoding@0.1.13))(vite@6.0.3(@types/node@20.11.6)(jiti@1.21.6)(less@4.2.0)(terser@5.27.0)(tsx@4.19.0)) + tailwind-merge: + specifier: ^2.2.0 + version: 2.2.1 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.1) unocss: specifier: ^0.65.1 version: 0.65.1(postcss@8.4.49)(rollup@4.28.1)(vite@6.0.3(@types/node@20.11.6)(jiti@1.21.6)(less@4.2.0)(terser@5.27.0)(tsx@4.19.0))(vue@3.5.13(typescript@5.6.3)) @@ -1422,6 +1434,11 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} + '@corvu/utils@0.4.2': + resolution: {integrity: sha512-Ox2kYyxy7NoXdKWdHeDEjZxClwzO4SKM8plAaVwmAJPxHMqA0rLOoAsa+hBDwRLpctf+ZRnAd/ykguuJidnaTA==} + peerDependencies: + solid-js: ^1.8 + '@develar/schema-utils@2.6.5': resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==} engines: {node: '>= 8.9.0'} @@ -2114,9 +2131,15 @@ packages: '@floating-ui/core@1.5.3': resolution: {integrity: sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==} + '@floating-ui/core@1.6.8': + resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==} + '@floating-ui/dom@1.5.4': resolution: {integrity: sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ==} + '@floating-ui/dom@1.6.12': + resolution: {integrity: sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==} + '@floating-ui/react-dom@2.0.6': resolution: {integrity: sha512-IB8aCRFxr8nFkdYZgH+Otd9EVQPJoynxeFRGTB8voPoZMRWo8XjYuCRgpI1btvuKY69XMiLnW+ym7zoBHM90Rw==} peerDependencies: @@ -2126,6 +2149,9 @@ packages: '@floating-ui/utils@0.2.1': resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} + '@floating-ui/utils@0.2.8': + resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} + '@fontsource/ubuntu@5.0.8': resolution: {integrity: sha512-lZY64hVXrnkt/+5jRfm0uMiRv+lmrIdnATAnDj1SPqebmI2UDf3KC9p4rOkIYsBOjOsD6seJ82GIQE067DSvWw==} @@ -2295,6 +2321,12 @@ packages: cpu: [x64] os: [win32] + '@internationalized/date@3.6.0': + resolution: {integrity: sha512-+z6ti+CcJnRlLHok/emGEsWQhe7kfSmEW+/6qCzvKY67YPh7YOBfvc7+/+NXq+zJlbArg30tYpqLjNgcAYv2YQ==} + + '@internationalized/number@3.6.0': + resolution: {integrity: sha512-PtrRcJVy7nw++wn4W2OuePQQfTqDzfusSuY1QTtui4wa7r+rGVtR75pO8CyKvHvzyQYi3Q1uO5sY0AsB4e65Bw==} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -2365,6 +2397,16 @@ packages: '@juggle/resize-observer@3.4.0': resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==} + '@kobalte/core@0.13.7': + resolution: {integrity: sha512-COhjWk1KnCkl3qMJDvdrOsvpTlJ9gMLdemkAn5SWfbPn/lxJYabejnNOk+b/ILGg7apzQycgbuo48qb8ppqsAg==} + peerDependencies: + solid-js: ^1.8.15 + + '@kobalte/utils@0.9.1': + resolution: {integrity: sha512-eeU60A3kprIiBDAfv9gUJX1tXGLuZiKMajUfSQURAF2pk4ZoMYiqIzmrMBvzcxP39xnYttgTyQEVLwiTZnrV4w==} + peerDependencies: + solid-js: ^1.8.8 + '@malept/cross-spawn-promise@1.1.1': resolution: {integrity: sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==} engines: {node: '>= 10'} @@ -3307,36 +3349,71 @@ packages: peerDependencies: solid-js: ^1.6.12 + '@solid-primitives/event-listener@2.3.3': + resolution: {integrity: sha512-DAJbl+F0wrFW2xmcV8dKMBhk9QLVLuBSW+TR4JmIfTaObxd13PuL7nqaXnaYKDWOYa6otB00qcCUIGbuIhSUgQ==} + peerDependencies: + solid-js: ^1.6.12 + '@solid-primitives/keyboard@1.2.6': resolution: {integrity: sha512-ZbXkzAwFs+6hyaZ2hT9uQ38iPZzGTjV6kWvVvJ3BDfKASg0dDDuhEZRKmpkmpLfnqOabV58BUkASJWMAA4dZCg==} peerDependencies: solid-js: ^1.6.12 + '@solid-primitives/keyed@1.2.3': + resolution: {integrity: sha512-Tlm2wCKcXEVxqd1speWjPhGvDhuuo/VeWSvNF6r2h77BUOHRKmNwz9uVKKMQmYSaLwiptJTp+fPZY2dOVPWQRQ==} + peerDependencies: + solid-js: ^1.6.12 + '@solid-primitives/map@0.4.9': resolution: {integrity: sha512-wMbIhfn24QDnNqJHRskFjKJ2bwvcx28/S0xBKoZdRdUaqIPZYWOVT8SM++dfWS44YdC2kJPF4RSTY1022aujLA==} peerDependencies: solid-js: ^1.6.12 + '@solid-primitives/media@2.2.9': + resolution: {integrity: sha512-QUmU62D4/d9YWx/4Dvr/UZasIkIpqNXz7wosA5GLmesRW9XlPa3G5M6uOmTw73SByHNTCw0D6x8bSdtvvLgzvQ==} + peerDependencies: + solid-js: ^1.6.12 + '@solid-primitives/memo@1.3.6': resolution: {integrity: sha512-3cefM0J+9gDDnYj4z7TZLBEDlV4kf/xtpIcagGRoCbMXO5eBIbAa3Um7HUFSpfCrj3G6X++qZ+JPfZyE9yL81Q==} peerDependencies: solid-js: ^1.6.12 + '@solid-primitives/props@3.1.11': + resolution: {integrity: sha512-jZAKWwvDRHjiydIumDgMj68qviIbowQ1ci7nkEAgzgvanNkhKSQV8iPgR2jMk1uv7S2ZqXYHslVQTgJel/TEyg==} + peerDependencies: + solid-js: ^1.6.12 + '@solid-primitives/refs@1.0.6': resolution: {integrity: sha512-ruh4YdVMxThEVnvqbpeLXKojW442vpFU8q7dSKtElGOTa31aKOAkRb9BTbdaTwVjN4BEq79fiiYIXozJNl4dSw==} peerDependencies: solid-js: ^1.6.12 + '@solid-primitives/resize-observer@2.0.26': + resolution: {integrity: sha512-KbPhwal6ML9OHeUTZszBbt6PYSMj89d4wVCLxlvDYL4U0+p+xlCEaqz6v9dkCwm/0Lb+Wed7W5T1dQZCP3JUUw==} + peerDependencies: + solid-js: ^1.6.12 + '@solid-primitives/rootless@1.4.3': resolution: {integrity: sha512-IPsfUhKsqQOxLtRMQWK2EZAYbL9RKJMLBelLwpaXl9+oa1tl5aNvA6GHgrNrK+85oUhiYh7/OuogO18AuHepqQ==} peerDependencies: solid-js: ^1.6.12 + '@solid-primitives/rootless@1.4.5': + resolution: {integrity: sha512-GFJE9GC3ojx0aUKqAUZmQPyU8fOVMtnVNrkdk2yS4kd17WqVSpXpoTmo9CnOwA+PG7FTzdIkogvfLQSLs4lrww==} + peerDependencies: + solid-js: ^1.6.12 + '@solid-primitives/scheduled@1.4.2': resolution: {integrity: sha512-duKaugDQtPk0v6MnkBuEalWk66/vA2G7zzoimQEvmUdh2+K2o8t908HIfI2NdBfwakQMQBV4epE3TFeN2Vsveg==} peerDependencies: solid-js: ^1.6.12 + '@solid-primitives/static-store@0.0.8': + resolution: {integrity: sha512-ZecE4BqY0oBk0YG00nzaAWO5Mjcny8Fc06CdbXadH9T9lzq/9GefqcSe/5AtdXqjvY/DtJ5C6CkcjPZO0o/eqg==} + peerDependencies: + solid-js: ^1.6.12 + '@solid-primitives/transition-group@1.0.4': resolution: {integrity: sha512-9nPg6HYAmEi7riH0C2bSCVw/2asgGSzHuN0yFFYyK9JgmXqJgyeyA+6thZbj7GgUQMRhtBxpH8yG7N2nEh8ttA==} peerDependencies: @@ -3352,6 +3429,11 @@ packages: peerDependencies: solid-js: ^1.6.12 + '@solid-primitives/utils@6.2.3': + resolution: {integrity: sha512-CqAwKb2T5Vi72+rhebSsqNZ9o67buYRdEJrIFzRXz3U59QqezuuxPsyzTSVCacwS5Pf109VRsgCJQoxKRoECZQ==} + peerDependencies: + solid-js: ^1.6.12 + '@solidjs/router@0.9.1': resolution: {integrity: sha512-kRY75piOQsyoH75E/RP6lr7uVGFCjeeCCCJx7Z2D1Vc6+I1yFQjLCvE+6agXGwqDoWi6vbETP1g7gmp/L1mNLg==} peerDependencies: @@ -3543,6 +3625,9 @@ packages: '@storybook/types@7.6.10': resolution: {integrity: sha512-hcS2HloJblaMpCAj2axgGV+53kgSRYPT0a1PG1IHsZaYQILfHSMmBqM8XzXXYTsgf9250kz3dqFX1l0n3EqMlQ==} + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + '@szmarczak/http-timer@1.1.2': resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} engines: {node: '>=6'} @@ -4806,6 +4891,10 @@ packages: resolution: {integrity: sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==} engines: {node: '>=6'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} @@ -8430,6 +8519,16 @@ packages: solid-js@1.9.3: resolution: {integrity: sha512-5ba3taPoZGt9GY3YlsCB24kCg0Lv/rie/HTD4kG6h4daZZz7+yK02xn8Vx8dLYBc9i6Ps5JwAbEiqjmKaLB3Ag==} + solid-presence@0.1.8: + resolution: {integrity: sha512-pWGtXUFWYYUZNbg5YpG5vkQJyOtzn2KXhxYaMx/4I+lylTLYkITOLevaCwMRN+liCVk0pqB6EayLWojNqBFECA==} + peerDependencies: + solid-js: ^1.8 + + solid-prevent-scroll@0.1.10: + resolution: {integrity: sha512-KplGPX2GHiWJLZ6AXYRql4M127PdYzfwvLJJXMkO+CMb8Np4VxqDAg5S8jLdwlEuBis/ia9DKw2M8dFx5u8Mhw==} + peerDependencies: + solid-js: ^1.8 + solid-refresh@0.6.3: resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==} peerDependencies: @@ -8680,6 +8779,11 @@ packages: tailwind-merge@2.2.1: resolution: {integrity: sha512-o+2GTLkthfa5YUt4JxPfzMIpQzZ3adD1vLVkvKE1Twl9UAhGsEbIZhHHZVRttyW177S8PDJI3bTQNaebyofK3Q==} + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + tailwindcss@3.4.1: resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==} engines: {node: '>=14.0.0'} @@ -8879,6 +8983,9 @@ packages: tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.19.0: resolution: {integrity: sha512-bV30kM7bsLZKZIOCHeMNVMJ32/LuJzLVajkQI/qf92J2Qr08ueLQvW00PUZGiuLPP760UINwupgUj8qrSCPUKg==} engines: {node: '>=18.0.0'} @@ -11532,6 +11639,11 @@ snapshots: '@colors/colors@1.5.0': optional: true + '@corvu/utils@0.4.2(solid-js@1.9.3)': + dependencies: + '@floating-ui/dom': 1.6.12 + solid-js: 1.9.3 + '@develar/schema-utils@2.6.5': dependencies: ajv: 6.12.6 @@ -12019,11 +12131,20 @@ snapshots: dependencies: '@floating-ui/utils': 0.2.1 + '@floating-ui/core@1.6.8': + dependencies: + '@floating-ui/utils': 0.2.8 + '@floating-ui/dom@1.5.4': dependencies: '@floating-ui/core': 1.5.3 '@floating-ui/utils': 0.2.1 + '@floating-ui/dom@1.6.12': + dependencies: + '@floating-ui/core': 1.6.8 + '@floating-ui/utils': 0.2.8 + '@floating-ui/react-dom@2.0.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@floating-ui/dom': 1.5.4 @@ -12032,6 +12153,8 @@ snapshots: '@floating-ui/utils@0.2.1': {} + '@floating-ui/utils@0.2.8': {} + '@fontsource/ubuntu@5.0.8': {} '@formatjs/ecma402-abstract@2.0.0': @@ -12172,6 +12295,14 @@ snapshots: '@img/sharp-win32-x64@0.33.2': optional: true + '@internationalized/date@3.6.0': + dependencies: + '@swc/helpers': 0.5.15 + + '@internationalized/number@3.6.0': + dependencies: + '@swc/helpers': 0.5.15 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -12275,6 +12406,29 @@ snapshots: '@juggle/resize-observer@3.4.0': {} + '@kobalte/core@0.13.7(solid-js@1.9.3)': + dependencies: + '@floating-ui/dom': 1.5.4 + '@internationalized/date': 3.6.0 + '@internationalized/number': 3.6.0 + '@kobalte/utils': 0.9.1(solid-js@1.9.3) + '@solid-primitives/props': 3.1.11(solid-js@1.9.3) + '@solid-primitives/resize-observer': 2.0.26(solid-js@1.9.3) + solid-js: 1.9.3 + solid-presence: 0.1.8(solid-js@1.9.3) + solid-prevent-scroll: 0.1.10(solid-js@1.9.3) + + '@kobalte/utils@0.9.1(solid-js@1.9.3)': + dependencies: + '@solid-primitives/event-listener': 2.3.1(solid-js@1.9.3) + '@solid-primitives/keyed': 1.2.3(solid-js@1.9.3) + '@solid-primitives/map': 0.4.9(solid-js@1.9.3) + '@solid-primitives/media': 2.2.9(solid-js@1.9.3) + '@solid-primitives/props': 3.1.11(solid-js@1.9.3) + '@solid-primitives/refs': 1.0.6(solid-js@1.9.3) + '@solid-primitives/utils': 6.2.2(solid-js@1.9.3) + solid-js: 1.9.3 + '@malept/cross-spawn-promise@1.1.1': dependencies: cross-spawn: 7.0.6 @@ -13393,6 +13547,11 @@ snapshots: '@solid-primitives/utils': 6.2.2(solid-js@1.9.3) solid-js: 1.9.3 + '@solid-primitives/event-listener@2.3.3(solid-js@1.9.3)': + dependencies: + '@solid-primitives/utils': 6.2.3(solid-js@1.9.3) + solid-js: 1.9.3 + '@solid-primitives/keyboard@1.2.6(solid-js@1.9.3)': dependencies: '@solid-primitives/event-listener': 2.3.1(solid-js@1.9.3) @@ -13400,31 +13559,66 @@ snapshots: '@solid-primitives/utils': 6.2.2(solid-js@1.9.3) solid-js: 1.9.3 + '@solid-primitives/keyed@1.2.3(solid-js@1.9.3)': + dependencies: + solid-js: 1.9.3 + '@solid-primitives/map@0.4.9(solid-js@1.9.3)': dependencies: '@solid-primitives/trigger': 1.0.9(solid-js@1.9.3) solid-js: 1.9.3 + '@solid-primitives/media@2.2.9(solid-js@1.9.3)': + dependencies: + '@solid-primitives/event-listener': 2.3.3(solid-js@1.9.3) + '@solid-primitives/rootless': 1.4.5(solid-js@1.9.3) + '@solid-primitives/static-store': 0.0.8(solid-js@1.9.3) + '@solid-primitives/utils': 6.2.3(solid-js@1.9.3) + solid-js: 1.9.3 + '@solid-primitives/memo@1.3.6(solid-js@1.9.3)': dependencies: '@solid-primitives/scheduled': 1.4.2(solid-js@1.9.3) '@solid-primitives/utils': 6.2.2(solid-js@1.9.3) solid-js: 1.9.3 + '@solid-primitives/props@3.1.11(solid-js@1.9.3)': + dependencies: + '@solid-primitives/utils': 6.2.3(solid-js@1.9.3) + solid-js: 1.9.3 + '@solid-primitives/refs@1.0.6(solid-js@1.9.3)': dependencies: '@solid-primitives/utils': 6.2.2(solid-js@1.9.3) solid-js: 1.9.3 + '@solid-primitives/resize-observer@2.0.26(solid-js@1.9.3)': + dependencies: + '@solid-primitives/event-listener': 2.3.3(solid-js@1.9.3) + '@solid-primitives/rootless': 1.4.5(solid-js@1.9.3) + '@solid-primitives/static-store': 0.0.8(solid-js@1.9.3) + '@solid-primitives/utils': 6.2.3(solid-js@1.9.3) + solid-js: 1.9.3 + '@solid-primitives/rootless@1.4.3(solid-js@1.9.3)': dependencies: '@solid-primitives/utils': 6.2.2(solid-js@1.9.3) solid-js: 1.9.3 + '@solid-primitives/rootless@1.4.5(solid-js@1.9.3)': + dependencies: + '@solid-primitives/utils': 6.2.3(solid-js@1.9.3) + solid-js: 1.9.3 + '@solid-primitives/scheduled@1.4.2(solid-js@1.9.3)': dependencies: solid-js: 1.9.3 + '@solid-primitives/static-store@0.0.8(solid-js@1.9.3)': + dependencies: + '@solid-primitives/utils': 6.2.3(solid-js@1.9.3) + solid-js: 1.9.3 + '@solid-primitives/transition-group@1.0.4(solid-js@1.9.3)': dependencies: solid-js: 1.9.3 @@ -13438,6 +13632,10 @@ snapshots: dependencies: solid-js: 1.9.3 + '@solid-primitives/utils@6.2.3(solid-js@1.9.3)': + dependencies: + solid-js: 1.9.3 + '@solidjs/router@0.9.1(solid-js@1.9.3)': dependencies: solid-js: 1.9.3 @@ -13553,7 +13751,7 @@ snapshots: '@storybook/global': 5.0.0 ts-dedent: 2.2.0 - '@storybook/addon-styling@1.3.7(@types/react@18.2.48)(encoding@0.1.13)(less@4.2.0)(postcss@8.4.49)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.6.3)(webpack@5.90.0(esbuild@0.18.20))': + '@storybook/addon-styling@1.3.7(@types/react@18.2.48)(encoding@0.1.13)(less@4.2.0)(postcss@8.4.49)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.6.3)(webpack@5.90.0(esbuild@0.23.1))': dependencies: '@babel/template': 7.22.15 '@babel/types': 7.23.6 @@ -13566,19 +13764,19 @@ snapshots: '@storybook/preview-api': 7.6.10 '@storybook/theming': 7.6.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/types': 7.6.10 - css-loader: 6.9.1(webpack@5.90.0(esbuild@0.18.20)) - less-loader: 11.1.4(less@4.2.0)(webpack@5.90.0(esbuild@0.18.20)) - postcss-loader: 7.3.4(postcss@8.4.49)(typescript@5.6.3)(webpack@5.90.0(esbuild@0.18.20)) + css-loader: 6.9.1(webpack@5.90.0(esbuild@0.23.1)) + less-loader: 11.1.4(less@4.2.0)(webpack@5.90.0(esbuild@0.23.1)) + postcss-loader: 7.3.4(postcss@8.4.49)(typescript@5.6.3)(webpack@5.90.0(esbuild@0.23.1)) prettier: 2.8.8 resolve-url-loader: 5.0.0 - sass-loader: 13.3.3(webpack@5.90.0(esbuild@0.18.20)) - style-loader: 3.3.4(webpack@5.90.0(esbuild@0.18.20)) + sass-loader: 13.3.3(webpack@5.90.0(esbuild@0.23.1)) + style-loader: 3.3.4(webpack@5.90.0(esbuild@0.23.1)) optionalDependencies: less: 4.2.0 postcss: 8.4.49 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - webpack: 5.90.0(esbuild@0.18.20) + webpack: 5.90.0(esbuild@0.23.1) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -14002,6 +14200,10 @@ snapshots: '@types/express': 4.17.21 file-system-cache: 2.3.0 + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + '@szmarczak/http-timer@1.1.2': dependencies: defer-to-connect: 1.1.3 @@ -15311,12 +15513,12 @@ snapshots: dependencies: '@babel/core': 7.25.2 - babel-loader@9.1.3(@babel/core@7.23.7)(webpack@5.90.0(esbuild@0.18.20)): + babel-loader@9.1.3(@babel/core@7.23.7)(webpack@5.90.0(esbuild@0.23.1)): dependencies: '@babel/core': 7.23.7 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.90.0(esbuild@0.18.20) + webpack: 5.90.0(esbuild@0.23.1) babel-plugin-istanbul@6.1.1: dependencies: @@ -15809,6 +16011,8 @@ snapshots: clsx@2.1.0: {} + clsx@2.1.1: {} + collapse-white-space@2.1.0: {} color-convert@1.9.3: @@ -15997,7 +16201,7 @@ snapshots: crypto-random-string@2.0.0: {} - css-loader@6.9.1(webpack@5.90.0(esbuild@0.18.20)): + css-loader@6.9.1(webpack@5.90.0(esbuild@0.23.1)): dependencies: icss-utils: 5.1.0(postcss@8.4.49) postcss: 8.4.49 @@ -16007,7 +16211,7 @@ snapshots: postcss-modules-values: 4.0.0(postcss@8.4.49) postcss-value-parser: 4.2.0 semver: 7.6.3 - webpack: 5.90.0(esbuild@0.18.20) + webpack: 5.90.0(esbuild@0.23.1) css-tree@3.1.0: dependencies: @@ -18079,16 +18283,16 @@ snapshots: dependencies: readable-stream: 2.3.8 - less-loader@11.1.4(less@4.2.0)(webpack@5.90.0(esbuild@0.18.20)): + less-loader@11.1.4(less@4.2.0)(webpack@5.90.0(esbuild@0.23.1)): dependencies: less: 4.2.0 - webpack: 5.90.0(esbuild@0.18.20) + webpack: 5.90.0(esbuild@0.23.1) less@4.2.0: dependencies: copy-anything: 2.0.6 parse-node-version: 1.0.1 - tslib: 2.6.2 + tslib: 2.8.1 optionalDependencies: errno: 0.1.8 graceful-fs: 4.2.11 @@ -19364,13 +19568,13 @@ snapshots: optionalDependencies: postcss: 8.4.33 - postcss-loader@7.3.4(postcss@8.4.49)(typescript@5.6.3)(webpack@5.90.0(esbuild@0.18.20)): + postcss-loader@7.3.4(postcss@8.4.49)(typescript@5.6.3)(webpack@5.90.0(esbuild@0.23.1)): dependencies: cosmiconfig: 8.3.6(typescript@5.6.3) jiti: 1.21.0 postcss: 8.4.49 semver: 7.6.3 - webpack: 5.90.0(esbuild@0.18.20) + webpack: 5.90.0(esbuild@0.23.1) transitivePeerDependencies: - typescript @@ -20017,10 +20221,10 @@ snapshots: parse-srcset: 1.0.2 postcss: 8.4.35 - sass-loader@13.3.3(webpack@5.90.0(esbuild@0.18.20)): + sass-loader@13.3.3(webpack@5.90.0(esbuild@0.23.1)): dependencies: neo-async: 2.6.2 - webpack: 5.90.0(esbuild@0.18.20) + webpack: 5.90.0(esbuild@0.23.1) sax@1.3.0: {} @@ -20276,6 +20480,16 @@ snapshots: seroval: 1.1.1 seroval-plugins: 1.1.1(seroval@1.1.1) + solid-presence@0.1.8(solid-js@1.9.3): + dependencies: + '@corvu/utils': 0.4.2(solid-js@1.9.3) + solid-js: 1.9.3 + + solid-prevent-scroll@0.1.10(solid-js@1.9.3): + dependencies: + '@corvu/utils': 0.4.2(solid-js@1.9.3) + solid-js: 1.9.3 + solid-refresh@0.6.3(solid-js@1.8.12): dependencies: '@babel/generator': 7.25.6 @@ -20472,9 +20686,9 @@ snapshots: strnum@1.0.5: {} - style-loader@3.3.4(webpack@5.90.0(esbuild@0.18.20)): + style-loader@3.3.4(webpack@5.90.0(esbuild@0.23.1)): dependencies: - webpack: 5.90.0(esbuild@0.18.20) + webpack: 5.90.0(esbuild@0.23.1) style-to-object@0.4.4: dependencies: @@ -20536,6 +20750,10 @@ snapshots: dependencies: '@babel/runtime': 7.23.8 + tailwindcss-animate@1.0.7(tailwindcss@3.4.1): + dependencies: + tailwindcss: 3.4.1 + tailwindcss@3.4.1: dependencies: '@alloc/quick-lru': 5.2.0 @@ -20626,16 +20844,16 @@ snapshots: type-fest: 0.16.0 unique-string: 2.0.0 - terser-webpack-plugin@5.3.10(esbuild@0.18.20)(webpack@5.90.0(esbuild@0.18.20)): + terser-webpack-plugin@5.3.10(esbuild@0.23.1)(webpack@5.90.0(esbuild@0.23.1)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.27.0 - webpack: 5.90.0(esbuild@0.18.20) + webpack: 5.90.0(esbuild@0.23.1) optionalDependencies: - esbuild: 0.18.20 + esbuild: 0.23.1 terser@5.27.0: dependencies: @@ -20751,6 +20969,8 @@ snapshots: tslib@2.6.2: {} + tslib@2.8.1: {} + tsx@4.19.0: dependencies: esbuild: 0.23.1 @@ -21411,7 +21631,7 @@ snapshots: webpack-virtual-modules@0.6.1: {} - webpack@5.90.0(esbuild@0.18.20): + webpack@5.90.0(esbuild@0.23.1): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.6 @@ -21434,7 +21654,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(esbuild@0.18.20)(webpack@5.90.0(esbuild@0.18.20)) + terser-webpack-plugin: 5.3.10(esbuild@0.23.1)(webpack@5.90.0(esbuild@0.23.1)) watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: