[FIX] chakra ui component is not full

This commit is contained in:
Edouard DUPIN 2025-01-13 23:49:04 +01:00
parent 2812d21782
commit 91defa42c2
6 changed files with 155 additions and 56 deletions

View File

@ -25,7 +25,7 @@ import { environment } from '@/environment';
import { App as SpaApp } from '@/scene/App';
import { USERS, USERS_COLLECTION } from '@/service/session';
import { hashLocalData } from '@/utils/sso';
import { Toaster } from './components/toaster';
import { Toaster } from './components/ui/toaster';
const AppEnvHint = () => {
const dialog = useDisclosure();

View File

@ -11,7 +11,6 @@ import {
Flex,
HStack,
IconButton,
Menu,
Text,
useDisclosure,
} from '@chakra-ui/react';
@ -33,6 +32,7 @@ import { requestSignIn, requestSignOut, requestSignUp } from '@/utils/sso';
import { useThemeMode } from '@/utils/theme-tools';
import { useSessionService } from '@/service/session';
import { MdHelp, MdHome, MdMore, MdOutlinePlaylistPlay, MdOutlineUploadFile, MdSupervisedUserCircle } from 'react-icons/md';
import { MenuContent, MenuItem, MenuRoot, MenuTrigger } from '../ui/menu';
export const TOP_BAR_HEIGHT = '50px';
@ -139,38 +139,36 @@ export const TopBar = ({ title, children }: TopBarProps) => {
</>
)}
{session?.state === SessionState.CONNECTED && (
<Menu.Root>
<Menu.Trigger asChild>
<MenuRoot>
<MenuTrigger asChild>
<IconButton
as={IconButton}
aria-label="Options"
{...BUTTON_TOP_BAR_PROPERTY}
width={TOP_BAR_HEIGHT}
><MdSupervisedUserCircle /></IconButton>
</Menu.Trigger>
<Menu.Positioner>
<Menu.Content>
<Menu.Item value="user" valueText="user" _hover={{}} color={mode('brand.800', 'brand.200')}>
<MdSupervisedUserCircle />
<Box flex="1">Sign in as {session?.login ?? 'Fail'}</Box>
</Menu.Item>
<Menu.Item value="Settings" valueText="Settings" onClick={onSettings}><LuSettings />Settings</Menu.Item>
<Menu.Item value="Help" valueText="Help" onClick={onHelp}><MdHelp /> Help</Menu.Item>
<Menu.Item value="Sign-out" valueText="Sign-out" onClick={onSignOut}>
<LuLogOut /> Sign-out
</Menu.Item>
{colorMode === 'light' ? (
<Menu.Item value="set-dark" valueText="set-dark" onClick={toggleColorMode}>
<LuMoon /> Set dark mode
</Menu.Item>
) : (
<Menu.Item value="set-light" valueText="set-light" onClick={toggleColorMode}>
<LuSun /> Set light mode
</Menu.Item>
)}
</Menu.Content>
</Menu.Positioner>
</Menu.Root>
</MenuTrigger>
<MenuContent>
<MenuItem value="user" valueText="user" _hover={{}} color={mode('brand.800', 'brand.200')}>
<MdSupervisedUserCircle />
<Box flex="1">Sign in as {session?.login ?? 'Fail'}</Box>
</MenuItem>
<MenuItem value="Settings" valueText="Settings" onClick={onSettings}><LuSettings />Settings</MenuItem>
<MenuItem value="Help" valueText="Help" onClick={onHelp}><MdHelp /> Help</MenuItem>
<MenuItem value="Sign-out" valueText="Sign-out" onClick={onSignOut}>
<LuLogOut /> Sign-out
</MenuItem>
{colorMode === 'light' ? (
<MenuItem value="set-dark" valueText="set-dark" onClick={toggleColorMode}>
<LuMoon /> Set dark mode
</MenuItem>
) : (
<MenuItem value="set-light" valueText="set-light" onClick={toggleColorMode}>
<LuSun /> Set light mode
</MenuItem>
)}
</MenuContent>
</MenuRoot>
)}
</Flex>
<Drawer.Root

View File

@ -2,9 +2,9 @@ import { useState } from 'react';
import {
IconButton,
Menu,
} from '@chakra-ui/react';
import { LuMenu } from 'react-icons/lu';
import { MenuContent, MenuItem, MenuRoot, MenuTrigger } from '../ui/menu';
export type MenuElement = {
name: string;
@ -20,26 +20,24 @@ export const ContextMenu = ({ elements }: ContextMenuProps) => {
return <></>;
}
return (
<Menu.Root
<MenuRoot
data-testid="context-menu">
<Menu.Trigger asChild
<MenuTrigger asChild
data-testid="context-menu_trigger">
{/* This is very stupid, we need to set as span to prevent a button in button... WTF */}
<IconButton as='span'>
<LuMenu />
</IconButton>
</Menu.Trigger>
<Menu.Positioner>
<Menu.Content
data-testid="context-menu_content">
{elements?.map((data) => (
<Menu.Item key={data.name} value={data.name} onClick={data.onClick}
data-testid="context-menu_item">
{data.name}
</Menu.Item>
))}
</Menu.Content>
</Menu.Positioner>
</Menu.Root>
</MenuTrigger>
<MenuContent
data-testid="context-menu_content">
{elements?.map((data) => (
<MenuItem key={data.name} value={data.name} onClick={data.onClick}
data-testid="context-menu_item">
{data.name}
</MenuItem>
))}
</MenuContent>
</MenuRoot>
);
};

View File

@ -0,0 +1,110 @@
"use client"
import { AbsoluteCenter, Menu as ChakraMenu, Portal } from "@chakra-ui/react"
import * as React from "react"
import { LuCheck, LuChevronRight } from "react-icons/lu"
interface MenuContentProps extends ChakraMenu.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
}
export const MenuContent = React.forwardRef<HTMLDivElement, MenuContentProps>(
function MenuContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraMenu.Positioner>
<ChakraMenu.Content ref={ref} {...rest} />
</ChakraMenu.Positioner>
</Portal>
)
},
)
export const MenuArrow = React.forwardRef<
HTMLDivElement,
ChakraMenu.ArrowProps
>(function MenuArrow(props, ref) {
return (
<ChakraMenu.Arrow ref={ref} {...props}>
<ChakraMenu.ArrowTip />
</ChakraMenu.Arrow>
)
})
export const MenuCheckboxItem = React.forwardRef<
HTMLDivElement,
ChakraMenu.CheckboxItemProps
>(function MenuCheckboxItem(props, ref) {
return (
<ChakraMenu.CheckboxItem ref={ref} {...props}>
<ChakraMenu.ItemIndicator hidden={false}>
<LuCheck />
</ChakraMenu.ItemIndicator>
{props.children}
</ChakraMenu.CheckboxItem>
)
})
export const MenuRadioItem = React.forwardRef<
HTMLDivElement,
ChakraMenu.RadioItemProps
>(function MenuRadioItem(props, ref) {
const { children, ...rest } = props
return (
<ChakraMenu.RadioItem ps="8" ref={ref} {...rest}>
<AbsoluteCenter axis="horizontal" left="4" asChild>
<ChakraMenu.ItemIndicator>
<LuCheck />
</ChakraMenu.ItemIndicator>
</AbsoluteCenter>
<ChakraMenu.ItemText>{children}</ChakraMenu.ItemText>
</ChakraMenu.RadioItem>
)
})
export const MenuItemGroup = React.forwardRef<
HTMLDivElement,
ChakraMenu.ItemGroupProps
>(function MenuItemGroup(props, ref) {
const { title, children, ...rest } = props
return (
<ChakraMenu.ItemGroup ref={ref} {...rest}>
{title && (
<ChakraMenu.ItemGroupLabel userSelect="none">
{title}
</ChakraMenu.ItemGroupLabel>
)}
{children}
</ChakraMenu.ItemGroup>
)
})
export interface MenuTriggerItemProps extends ChakraMenu.ItemProps {
startIcon?: React.ReactNode
}
export const MenuTriggerItem = React.forwardRef<
HTMLDivElement,
MenuTriggerItemProps
>(function MenuTriggerItem(props, ref) {
const { startIcon, children, ...rest } = props
return (
<ChakraMenu.TriggerItem ref={ref} {...rest}>
{startIcon}
{children}
<LuChevronRight />
</ChakraMenu.TriggerItem>
)
})
export const MenuRadioItemGroup = ChakraMenu.RadioItemGroup
export const MenuContextTrigger = ChakraMenu.ContextTrigger
export const MenuRoot = ChakraMenu.Root
export const MenuSeparator = ChakraMenu.Separator
export const MenuItem = ChakraMenu.Item
export const MenuItemText = ChakraMenu.ItemText
export const MenuItemCommand = ChakraMenu.ItemCommand
export const MenuTrigger = ChakraMenu.Trigger

View File

@ -9,13 +9,10 @@ import {
Toast,
createToaster,
} from "@chakra-ui/react"
import { useCallback } from "react";
export const toaster = createToaster({
duration: 3000,
placement: 'top-end',
// offset: { top: '50px' },
// variant: 'solid',
placement: "bottom-end",
pauseOnPageIdle: true,
})
export const toasterAPIError = (error: RestErrorResponse) => {
@ -28,13 +25,9 @@ export const toasterAPIError = (error: RestErrorResponse) => {
export const Toaster = () => {
return (
<Portal>
<ChakraToaster
toaster={toaster}
insetInline={{ mdDown: "1rem" }}
width={{ md: "356px" }}
>
<ChakraToaster toaster={toaster} insetInline={{ mdDown: "4" }}>
{(toast) => (
<Toast.Root>
<Toast.Root width={{ md: "sm" }}>
{toast.type === "loading" ? (
<Spinner size="sm" color="blue.solid" />
) : (

View File

@ -7,7 +7,7 @@ import { DependencyList, useCallback, useEffect, useState } from 'react';
import { RestErrorResponse } from '@/back-api';
import { isNullOrUndefined } from '@/utils/validator';
import { toasterAPIError } from '@/components/toaster';
import { toasterAPIError } from '@/components/ui/toaster';
export type DataStoreType<TYPE> = {
isLoading: boolean;