[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 { App as SpaApp } from '@/scene/App';
import { USERS, USERS_COLLECTION } from '@/service/session'; import { USERS, USERS_COLLECTION } from '@/service/session';
import { hashLocalData } from '@/utils/sso'; import { hashLocalData } from '@/utils/sso';
import { Toaster } from './components/toaster'; import { Toaster } from './components/ui/toaster';
const AppEnvHint = () => { const AppEnvHint = () => {
const dialog = useDisclosure(); const dialog = useDisclosure();

View File

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

View File

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

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