refactor(core): remove all MUI related components and utilities (#4941)

This commit is contained in:
Cats Juice
2023-11-20 10:51:28 +08:00
committed by GitHub
parent 4ef1f4c046
commit 57d42bf491
59 changed files with 335 additions and 2520 deletions

View File

@@ -27,9 +27,6 @@
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.1",
"@emotion/server": "^11.11.0", "@emotion/server": "^11.11.0",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@mui/base": "5.0.0-beta.19",
"@mui/icons-material": "^5.14.14",
"@mui/material": "^5.14.14",
"@popperjs/core": "^2.11.8", "@popperjs/core": "^2.11.8",
"@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-collapsible": "^1.0.3",

View File

@@ -1,4 +1,3 @@
import { Skeleton } from '@mui/material';
import { assignInlineVars } from '@vanilla-extract/dynamic'; import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx'; import clsx from 'clsx';
import { useAtom, useAtomValue } from 'jotai'; import { useAtom, useAtomValue } from 'jotai';
@@ -6,6 +5,7 @@ import { debounce } from 'lodash-es';
import type { PropsWithChildren, ReactElement } from 'react'; import type { PropsWithChildren, ReactElement } from 'react';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { Skeleton } from '../../ui/skeleton';
import { fallbackHeaderStyle, fallbackStyle } from './fallback.css'; import { fallbackHeaderStyle, fallbackStyle } from './fallback.css';
import { import {
floatingMaxWidth, floatingMaxWidth,

View File

@@ -1,7 +1,6 @@
import { EditorContainer } from '@blocksuite/editor'; import { EditorContainer } from '@blocksuite/editor';
import { assertExists } from '@blocksuite/global/utils'; import { assertExists } from '@blocksuite/global/utils';
import type { Page } from '@blocksuite/store'; import type { Page } from '@blocksuite/store';
import { Skeleton } from '@mui/material';
import clsx from 'clsx'; import clsx from 'clsx';
import { use } from 'foxact/use'; import { use } from 'foxact/use';
import type { CSSProperties, ReactElement } from 'react'; import type { CSSProperties, ReactElement } from 'react';
@@ -17,6 +16,7 @@ import {
import type { FallbackProps } from 'react-error-boundary'; import type { FallbackProps } from 'react-error-boundary';
import { ErrorBoundary } from 'react-error-boundary'; import { ErrorBoundary } from 'react-error-boundary';
import { Skeleton } from '../../ui/skeleton';
import { import {
blockSuiteEditorHeaderStyle, blockSuiteEditorHeaderStyle,
blockSuiteEditorStyle, blockSuiteEditorStyle,

View File

@@ -2,7 +2,6 @@ import { WorkspaceFlavour } from '@affine/env/workspace';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import type { RootWorkspaceMetadata } from '@affine/workspace/atom'; import type { RootWorkspaceMetadata } from '@affine/workspace/atom';
import { CollaborationIcon, SettingsIcon } from '@blocksuite/icons'; import { CollaborationIcon, SettingsIcon } from '@blocksuite/icons';
import { Skeleton } from '@mui/material';
import { Avatar } from '@toeverything/components/avatar'; import { Avatar } from '@toeverything/components/avatar';
import { Divider } from '@toeverything/components/divider'; import { Divider } from '@toeverything/components/divider';
import { Tooltip } from '@toeverything/components/tooltip'; import { Tooltip } from '@toeverything/components/tooltip';
@@ -12,6 +11,7 @@ import { getBlockSuiteWorkspaceAtom } from '@toeverything/infra/__internal__/wor
import { useAtomValue } from 'jotai/react'; import { useAtomValue } from 'jotai/react';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { Skeleton } from '../../../ui/skeleton';
import { import {
StyledCard, StyledCard,
StyledIconContainer, StyledIconContainer,

View File

@@ -1,13 +0,0 @@
import { Skeleton } from '@mui/material';
import { memo } from 'react';
export const ListSkeleton = memo(function ListItemSkeleton() {
return (
<>
<Skeleton animation="wave" height={40} />
<Skeleton animation="wave" height={40} />
<Skeleton animation="wave" height={40} />
<Skeleton animation="wave" height={40} />
</>
);
});

View File

@@ -1,4 +1,3 @@
import { useMediaQuery, useTheme } from '@mui/material';
import clsx from 'clsx'; import clsx from 'clsx';
import { import {
type BaseSyntheticEvent, type BaseSyntheticEvent,
@@ -8,12 +7,6 @@ import {
import * as styles from './page-list.css'; import * as styles from './page-list.css';
export const useIsSmallDevices = () => {
const theme = useTheme();
const isSmallDevices = useMediaQuery(theme.breakpoints.down(900));
return isSmallDevices;
};
export function isToday(date: Date): boolean { export function isToday(date: Date): boolean {
const today = new Date(); const today = new Date();
return ( return (

View File

@@ -1,5 +1,4 @@
import { Skeleton } from '@mui/material'; import { Skeleton } from '../../ui/skeleton';
import { SettingHeader } from './setting-header'; import { SettingHeader } from './setting-header';
import { SettingRow } from './setting-row'; import { SettingRow } from './setting-row';
import { SettingWrapper } from './wrapper'; import { SettingWrapper } from './wrapper';

View File

@@ -1,12 +1,11 @@
import { Skeleton } from '@mui/material';
import { FlexWrapper } from '../../ui/layout'; import { FlexWrapper } from '../../ui/layout';
import { Skeleton } from '../../ui/skeleton';
export const WorkspaceListItemSkeleton = () => { export const WorkspaceListItemSkeleton = () => {
return ( return (
<FlexWrapper <FlexWrapper
alignItems="center" alignItems="center"
style={{ padding: '0 8px', height: 30, marginBottom: 4 }} style={{ padding: '0 24px', height: 30, marginBottom: 4 }}
> >
<Skeleton <Skeleton
variant="circular" variant="circular"
@@ -14,7 +13,12 @@ export const WorkspaceListItemSkeleton = () => {
height={14} height={14}
style={{ marginRight: 10 }} style={{ marginRight: 10 }}
/> />
<Skeleton variant="rectangular" height={16} style={{ flexGrow: 1 }} /> <Skeleton
variant="rectangular"
height={16}
width={0}
style={{ flexGrow: 1 }}
/>
</FlexWrapper> </FlexWrapper>
); );
}; };

View File

@@ -2,8 +2,6 @@ import { lightCssVariables } from '@toeverything/theme';
import type { ComplexStyleRule } from '@vanilla-extract/css'; import type { ComplexStyleRule } from '@vanilla-extract/css';
import { globalStyle, style } from '@vanilla-extract/css'; import { globalStyle, style } from '@vanilla-extract/css';
import { breakpoints } from '../../styles/mui-theme';
export const appStyle = style({ export const appStyle = style({
width: '100%', width: '100%',
position: 'relative', position: 'relative',
@@ -134,10 +132,10 @@ export const toolStyle = style({
flexDirection: 'column', flexDirection: 'column',
gap: '12px', gap: '12px',
'@media': { '@media': {
[breakpoints.down('md', true)]: { 'screen and (max-width: 960px)': {
right: 'calc((100vw - 640px) * 3 / 19 + 14px)', right: 'calc((100vw - 640px) * 3 / 19 + 14px)',
}, },
[breakpoints.down('sm', true)]: { 'screen and (max-width: 640px)': {
right: '5px', right: '5px',
bottom: '5px', bottom: '5px',
}, },
@@ -149,10 +147,10 @@ export const toolStyle = style({
'&[data-in-trash-page="true"]': { '&[data-in-trash-page="true"]': {
bottom: '70px', bottom: '70px',
'@media': { '@media': {
[breakpoints.down('md', true)]: { 'screen and (max-width: 960px)': {
bottom: '80px', bottom: '80px',
}, },
[breakpoints.down('sm', true)]: { 'screen and (max-width: 640px)': {
bottom: '85px', bottom: '85px',
}, },
print: { print: {

View File

@@ -1,6 +1,4 @@
export * from './components/list-skeleton';
export * from './styles'; export * from './styles';
export * from './ui/breadcrumbs';
export * from './ui/button'; export * from './ui/button';
export * from './ui/checkbox'; export * from './ui/checkbox';
export * from './ui/empty'; export * from './ui/empty';
@@ -8,12 +6,8 @@ export * from './ui/input';
export * from './ui/layout'; export * from './ui/layout';
export * from './ui/lottie/collections-icon'; export * from './ui/lottie/collections-icon';
export * from './ui/lottie/delete-icon'; export * from './ui/lottie/delete-icon';
export * from './ui/menu';
export * from './ui/mui';
export * from './ui/popper';
export * from './ui/scrollbar'; export * from './ui/scrollbar';
export * from './ui/shared/container'; export * from './ui/skeleton';
export * from './ui/switch'; export * from './ui/switch';
export * from './ui/table'; export * from './ui/table';
export * from './ui/toast'; export * from './ui/toast';
export * from './ui/tree-view';

View File

@@ -1,3 +1,2 @@
export * from './helper'; export * from './helper';
export * from './mui-theme'; export * from './styled';
export * from './mui-theme-provider';

View File

@@ -1,3 +0,0 @@
import { alpha, css, keyframes, styled } from '@mui/material/styles';
export { alpha, css, keyframes, styled };

View File

@@ -1,86 +0,0 @@
import type {
Breakpoint,
BreakpointsOptions,
ThemeOptions,
} from '@mui/material';
export const muiThemes = {
breakpoints: {
values: {
xs: 0,
sm: 640,
md: 960,
lg: 1280,
xl: 1920,
},
},
} satisfies ThemeOptions;
// Ported from mui
// See https://github.com/mui/material-ui/blob/eba90da5359ff9c58b02800dfe468dc6c0b95bd2/packages/mui-system/src/createTheme/createBreakpoints.js
// License under MIT
function createBreakpoints(breakpoints: BreakpointsOptions): Readonly<
Omit<BreakpointsOptions, 'up' | 'down'> & {
up: (key: Breakpoint | number, pure?: boolean) => string;
down: (key: Breakpoint | number, pure?: boolean) => string;
}
> {
const {
// The breakpoint **start** at this value.
// For instance with the first breakpoint xs: [xs, sm).
values = {
xs: 0, // phone
sm: 600, // tablet
md: 900, // small laptop
lg: 1200, // desktop
xl: 1536, // large screen
},
unit = 'px',
step = 5,
...other
} = breakpoints;
const keys = Object.keys(values) as ['xs', 'sm', 'md', 'lg', 'xl'];
function up(key: Breakpoint | number, pure = false) {
const value = typeof key === 'number' ? key : values[key];
const original = `(min-width:${value}${unit})`;
if (pure) {
return original;
}
return `@media ${original}`;
}
function down(key: Breakpoint | number, pure = false) {
const value = typeof key === 'number' ? key : values[key];
const original = `(max-width:${value - step / 100}${unit})`;
if (pure) {
return original;
}
return `@media ${original}`;
}
return {
keys,
values,
up,
down,
unit,
// between,
// only,
// not,
...other,
};
}
/**
* @example
* ```ts
* export const iconButtonStyle = style({
* [breakpoints.up('sm')]: {
* padding: '6px'
* },
* });
* ```
*/
export const breakpoints = createBreakpoints(muiThemes.breakpoints);

View File

@@ -0,0 +1,3 @@
import styled from '@emotion/styled';
export { styled };

View File

@@ -1,14 +0,0 @@
import type { BreadcrumbsProps } from '@mui/material/Breadcrumbs';
import MuiBreadcrumbs from '@mui/material/Breadcrumbs';
import type { ComponentType } from 'react';
import { styled } from '../../styles';
const StyledMuiBreadcrumbs = styled(MuiBreadcrumbs)(() => {
return {
color: 'var(--affine-text-primary-color)',
};
});
export const Breadcrumbs: ComponentType<BreadcrumbsProps> =
StyledMuiBreadcrumbs;

View File

@@ -1,60 +0,0 @@
import { styled } from '../../styles';
import type { ButtonProps } from './interface';
import { getButtonColors } from './utils';
export const LoadingContainer = styled('div')<Pick<ButtonProps, 'type'>>(({
theme,
type = 'default',
}) => {
const { color } = getButtonColors(theme, type, false);
return `
margin: 0px auto;
width: 38px;
text-align: center;
.load {
width: 8px;
height: 8px;
background-color: ${color};
border-radius: 100%;
display: inline-block;
-webkit-animation: bouncedelay 1.4s infinite ease-in-out;
animation: bouncedelay 1.4s infinite ease-in-out;
/* Prevent first frame from flickering when animation starts */
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.load1 {
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}
.load2 {
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}
@-webkit-keyframes bouncedelay {
0%, 80%, 100% { -webkit-transform: scale(0) }
40% { -webkit-transform: scale(1.0) }
}
@keyframes bouncedelay {
0%, 80%, 100% {
transform: scale(0);
-webkit-transform: scale(0);
} 40% {
transform: scale(1.0);
-webkit-transform: scale(1.0);
}
}
`;
});
export const Loading = ({ type }: Pick<ButtonProps, 'type'>) => {
return (
<LoadingContainer type={type} className="load-container">
<div className="load load1"></div>
<div className="load load2"></div>
<div className="load"></div>
</LoadingContainer>
);
};

View File

@@ -1,9 +1,6 @@
import type { Theme } from '@mui/material';
import type { ButtonProps } from './interface'; import type { ButtonProps } from './interface';
export const getButtonColors = ( export const getButtonColors = (
_theme: Theme,
type: ButtonProps['type'], type: ButtonProps['type'],
disabled: boolean, disabled: boolean,
extend?: { extend?: {

View File

@@ -1,6 +0,0 @@
/**
* @deprecated
* Use @toeverything/components/menu instead, this component only used in bookmark plugin, since it support set anchor as Range
*/
export * from './menu-item';
export * from './pure-menu';

View File

@@ -1,44 +0,0 @@
import type { HTMLAttributes, PropsWithChildren, ReactElement } from 'react';
import { forwardRef } from 'react';
import {
StyledContent,
StyledEndIconWrapper,
StyledMenuItem,
StyledStartIconWrapper,
} from './styles';
export type IconMenuProps = PropsWithChildren<{
icon?: ReactElement;
endIcon?: ReactElement;
iconSize?: number;
disabled?: boolean;
active?: boolean;
disableHover?: boolean;
userFocused?: boolean;
gap?: string;
fontSize?: string;
}> &
HTMLAttributes<HTMLButtonElement>;
export const MenuItem = forwardRef<HTMLButtonElement, IconMenuProps>(
({ endIcon, icon, children, gap, fontSize, iconSize, ...props }, ref) => {
return (
<StyledMenuItem ref={ref} {...props}>
{icon && (
<StyledStartIconWrapper iconSize={iconSize} gap={gap}>
{icon}
</StyledStartIconWrapper>
)}
<StyledContent fontSize={fontSize}>{children}</StyledContent>
{endIcon && (
<StyledEndIconWrapper iconSize={iconSize} gap={gap}>
{endIcon}
</StyledEndIconWrapper>
)}
</StyledMenuItem>
);
}
);
MenuItem.displayName = 'MenuItem';
export default MenuItem;

View File

@@ -1,24 +0,0 @@
import type { CSSProperties } from 'react';
import type { PurePopperProps } from '../popper';
import { PurePopper } from '../popper';
import { StyledMenuWrapper } from './styles';
export type PureMenuProps = PurePopperProps & {
width?: CSSProperties['width'];
height?: CSSProperties['height'];
};
export const PureMenu = ({
children,
placement,
width,
...otherProps
}: PureMenuProps) => {
return (
<PurePopper placement={placement} {...otherProps}>
<StyledMenuWrapper width={width} placement={placement}>
{children}
</StyledMenuWrapper>
</PurePopper>
);
};

View File

@@ -1,115 +0,0 @@
import type { CSSProperties } from 'react';
import { displayFlex, styled, textEllipsis } from '../../styles';
import StyledPopperContainer from '../shared/container';
export const StyledMenuWrapper = styled(StyledPopperContainer, {
shouldForwardProp: propName =>
!['width', 'height'].includes(propName as string),
})<{
width?: CSSProperties['width'];
height?: CSSProperties['height'];
}>(({ width, height }) => {
return {
width,
height,
minWidth: '200px',
background: 'var(--affine-white)',
padding: '8px 4px',
fontSize: '14px',
backgroundColor: 'var(--affine-white)',
boxShadow: 'var(--affine-menu-shadow)',
userSelect: 'none',
};
});
export const StyledStartIconWrapper = styled('div')<{
gap?: CSSProperties['gap'];
iconSize?: CSSProperties['fontSize'];
}>(({ gap, iconSize }) => {
return {
display: 'flex',
marginRight: gap ? gap : '12px',
fontSize: iconSize ? iconSize : '20px',
color: 'var(--affine-icon-color)',
};
});
export const StyledEndIconWrapper = styled('div')<{
gap?: CSSProperties['gap'];
iconSize?: CSSProperties['fontSize'];
}>(({ gap, iconSize }) => {
return {
display: 'flex',
marginLeft: gap ? gap : '12px',
fontSize: iconSize ? iconSize : '20px',
color: 'var(--affine-icon-color)',
};
});
export const StyledContent = styled('div')<{
fontSize?: CSSProperties['fontSize'];
}>(({ fontSize }) => {
return {
textAlign: 'left',
flexGrow: 1,
fontSize: fontSize ? fontSize : 'var(--affine-font-base)',
...textEllipsis(1),
};
});
export const StyledMenuItem = styled('button')<{
isDir?: boolean;
disabled?: boolean;
active?: boolean;
disableHover?: boolean;
userFocused?: boolean;
}>(({
isDir = false,
disabled = false,
active = false,
disableHover = false,
userFocused = false,
}) => {
return {
width: '100%',
borderRadius: '5px',
padding: '0 14px',
fontSize: 'var(--affine-font-sm)',
height: '32px',
...displayFlex('flex-start', 'center'),
cursor: isDir ? 'pointer' : '',
position: 'relative',
backgroundColor: 'transparent',
color: disabled
? 'var(--affine-text-disable-color)'
: 'var(--affine-text-primary-color)',
svg: {
color: disabled
? 'var(--affine-text-disable-color)'
: 'var(--affine-icon-color)',
},
...(disabled
? {
cursor: 'not-allowed',
pointerEvents: 'none',
}
: {}),
':hover':
disabled || disableHover
? {}
: {
backgroundColor: 'var(--affine-hover-color)',
},
...(userFocused && !disabled
? {
backgroundColor: 'var(--affine-hover-color)',
}
: {}),
...(active && !disabled
? {
backgroundColor: 'var(--affine-hover-color)',
}
: {}),
};
});

View File

@@ -1,19 +0,0 @@
import { ClickAwayListener as MuiClickAwayListener } from '@mui/base/ClickAwayListener';
import MuiAvatar from '@mui/material/Avatar';
import MuiBreadcrumbs from '@mui/material/Breadcrumbs';
import MuiCollapse from '@mui/material/Collapse';
import MuiFade from '@mui/material/Fade';
import MuiGrow from '@mui/material/Grow';
import MuiSkeleton from '@mui/material/Skeleton';
import MuiSlide from '@mui/material/Slide';
export {
MuiAvatar,
MuiBreadcrumbs,
MuiClickAwayListener,
MuiCollapse,
MuiFade,
MuiGrow,
MuiSkeleton,
MuiSlide,
};

View File

@@ -1,3 +0,0 @@
export * from './interface';
export * from './popper';
export * from './pure-popper';

View File

@@ -1,64 +0,0 @@
import {
type PopperPlacementType,
type PopperProps as PopperUnstyledProps,
} from '@mui/base/Popper';
import type { CSSProperties, ReactElement, ReactNode, Ref } from 'react';
export type VirtualElement = {
getBoundingClientRect: () => ClientRect | DOMRect;
contextElement?: Element;
};
export type PopperHandler = {
setVisible: (visible: boolean) => void;
};
export type PopperArrowProps = {
placement?: PopperPlacementType;
};
export type PopperProps = {
// Popover content
content?: ReactNode;
// Popover trigger
children: ReactElement;
// Whether the default is implicit
defaultVisible?: boolean;
// Used to manually control the visibility of the Popover
visible?: boolean;
// TODO: support focus
trigger?: 'hover' | 'click' | 'focus' | ('click' | 'hover' | 'focus')[];
// How long does it take for the mouse to display the Popover, in milliseconds
pointerEnterDelay?: number;
// How long does it take to hide the Popover after the mouse moves out, in milliseconds
pointerLeaveDelay?: number;
// Callback fired when the component closed or open
onVisibleChange?: (visible: boolean) => void;
// Popover container style
popoverStyle?: CSSProperties;
// Popover container class name
popoverClassName?: string;
// Anchor class name
anchorClassName?: string;
// Popover z-index
zIndex?: number;
offset?: [number, number];
showArrow?: boolean;
popperHandlerRef?: Ref<PopperHandler>;
onClickAway?: () => void;
triggerContainerStyle?: CSSProperties;
} & Omit<PopperUnstyledProps, 'open' | 'content'>;

View File

@@ -1,97 +0,0 @@
import type { CSSProperties } from 'react';
import { forwardRef } from 'react';
import { styled } from '../../styles';
import type { PopperArrowProps } from './interface';
export const PopperArrow = forwardRef<HTMLElement, PopperArrowProps>(
function PopperArrow({ placement }, ref) {
return <StyledArrow placement={placement} ref={ref} />;
}
);
const getArrowStyle = (
placement: PopperArrowProps['placement'] = 'bottom',
backgroundColor: CSSProperties['backgroundColor']
) => {
if (placement.indexOf('bottom') === 0) {
return {
top: 0,
left: 0,
marginTop: '-0.9em',
width: '3em',
height: '1em',
'&::before': {
borderWidth: '0 1em 1em 1em',
borderColor: `transparent transparent ${backgroundColor} transparent`,
},
};
}
if (placement.indexOf('top') === 0) {
return {
bottom: 0,
left: 0,
marginBottom: '-0.9em',
width: '3em',
height: '1em',
'&::before': {
borderWidth: '1em 1em 0 1em',
borderColor: `${backgroundColor} transparent transparent transparent`,
},
};
}
if (placement.indexOf('left') === 0) {
return {
right: 0,
marginRight: '-0.9em',
height: '3em',
width: '1em',
'&::before': {
borderWidth: '1em 0 1em 1em',
borderColor: `transparent transparent transparent ${backgroundColor}`,
},
};
}
if (placement.indexOf('right') === 0) {
return {
left: 0,
marginLeft: '-0.9em',
height: '3em',
width: '1em',
'&::before': {
borderWidth: '1em 1em 1em 0',
borderColor: `transparent ${backgroundColor} transparent transparent`,
},
};
}
return {
display: 'none',
};
};
const StyledArrow = styled('span')<{
placement?: PopperArrowProps['placement'];
}>(({ placement }) => {
return {
position: 'absolute',
fontSize: '7px',
width: '3em',
'::before': {
content: '""',
margin: 'auto',
display: 'block',
width: 0,
height: 0,
borderStyle: 'solid',
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
},
...getArrowStyle(placement, 'var(--affine-tooltip)'),
};
});

View File

@@ -1,300 +0,0 @@
import { ClickAwayListener } from '@mui/base/ClickAwayListener';
import { Popper as PopperUnstyled } from '@mui/base/Popper';
import Grow from '@mui/material/Grow';
import type { CSSProperties, PointerEvent } from 'react';
import {
cloneElement,
useEffect,
useImperativeHandle,
useMemo,
useRef,
useState,
} from 'react';
import { styled } from '../../styles';
import type { PopperProps, VirtualElement } from './interface';
export const Popper = ({
children,
content,
anchorEl: propsAnchorEl,
placement = 'top-start',
defaultVisible = false,
visible: propsVisible,
trigger = 'hover',
pointerEnterDelay = 500,
pointerLeaveDelay = 100,
onVisibleChange,
popoverStyle,
popoverClassName,
anchorClassName,
zIndex,
offset = [0, 5],
showArrow = false,
popperHandlerRef,
onClick,
onClickAway,
onPointerEnter,
onPointerLeave,
triggerContainerStyle = {},
...popperProps
}: PopperProps) => {
const [anchorEl, setAnchorEl] = useState<VirtualElement>();
const [visible, setVisible] = useState(defaultVisible);
//const [arrowRef, setArrowRef] = useState<HTMLElement>();
const arrowRef = null;
const pointerLeaveTimer = useRef<number>();
const pointerEnterTimer = useRef<number>();
const visibleControlledByParent = typeof propsVisible !== 'undefined';
const isAnchorCustom = typeof propsAnchorEl !== 'undefined';
const hasHoverTrigger = useMemo(() => {
return (
trigger === 'hover' ||
(Array.isArray(trigger) && trigger.includes('hover'))
);
}, [trigger]);
const hasClickTrigger = useMemo(() => {
return (
trigger === 'click' ||
(Array.isArray(trigger) && trigger.includes('click'))
);
}, [trigger]);
const onPointerEnterHandler = (e: PointerEvent<HTMLDivElement>) => {
onPointerEnter?.(e);
if (!hasHoverTrigger || visibleControlledByParent) {
return;
}
window.clearTimeout(pointerLeaveTimer.current);
pointerEnterTimer.current = window.window.setTimeout(() => {
setVisible(true);
}, pointerEnterDelay);
};
const onPointerLeaveHandler = (e: PointerEvent<HTMLDivElement>) => {
onPointerLeave?.(e);
if (!hasHoverTrigger || visibleControlledByParent) {
return;
}
window.clearTimeout(pointerEnterTimer.current);
pointerLeaveTimer.current = window.window.setTimeout(() => {
setVisible(false);
}, pointerLeaveDelay);
};
useEffect(() => {
onVisibleChange?.(visible);
}, [visible, onVisibleChange]);
useImperativeHandle(popperHandlerRef, () => {
return {
setVisible: (visible: boolean) => {
!visibleControlledByParent && setVisible(visible);
},
};
});
const mergedClass = [anchorClassName, children.props.className]
.filter(Boolean)
.join(' ');
return (
<ClickAwayListener
onClickAway={() => {
if (visibleControlledByParent) {
onClickAway?.();
} else {
setVisible(false);
}
}}
>
<Container style={triggerContainerStyle}>
{cloneElement(children, {
ref: (dom: HTMLDivElement) => setAnchorEl(dom),
onClick: (e: MouseEvent) => {
children.props.onClick?.(e);
if (!hasClickTrigger || visibleControlledByParent) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
onClick?.(e);
return;
}
setVisible(!visible);
},
onPointerEnter: onPointerEnterHandler,
onPointerLeave: onPointerLeaveHandler,
...(mergedClass
? {
className: mergedClass,
}
: {}),
})}
{content && (
<BasicStyledPopper
open={visibleControlledByParent ? propsVisible : visible}
zIndex={zIndex}
anchorEl={isAnchorCustom ? propsAnchorEl : anchorEl}
placement={placement}
transition
modifiers={[
{
name: 'offset',
options: {
offset,
},
},
{
name: 'arrow',
enabled: showArrow,
options: {
element: arrowRef,
},
},
]}
{...popperProps}
>
{({ TransitionProps }) => (
<Grow {...TransitionProps}>
<div
onPointerEnter={onPointerEnterHandler}
onPointerLeave={onPointerLeaveHandler}
style={popoverStyle}
className={popoverClassName}
onClick={() => {
if (hasClickTrigger && !visibleControlledByParent) {
setVisible(false);
}
}}
>
{showArrow ? (
placement.indexOf('bottom') === 0 ? (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="11"
height="6"
viewBox="0 0 11 6"
fill="none"
>
<path
d="M6.38889 0.45C5.94444 -0.15 5.05555 -0.150001 4.61111 0.449999L0.499999 6L10.5 6L6.38889 0.45Z"
style={{ fill: 'var(--affine-tooltip)' }}
/>
</svg>
{content}
</div>
) : placement.indexOf('top') === 0 ? (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
{content}
<svg
xmlns="http://www.w3.org/2000/svg"
width="11"
height="6"
viewBox="0 0 11 6"
fill="none"
>
<path
d="M4.61111 5.55C5.05556 6.15 5.94445 6.15 6.38889 5.55L10.5 -4.76837e-07H0.5L4.61111 5.55Z"
style={{ fill: 'var(--affine-tooltip)' }}
/>
</svg>
</div>
) : placement.indexOf('left') === 0 ? (
<>
{content}
<svg
xmlns="http://www.w3.org/2000/svg"
width="6"
height="10"
viewBox="0 0 6 10"
fill="none"
>
<path
d="M5.55 5.88889C6.15 5.44444 6.15 4.55555 5.55 4.11111L-4.76837e-07 0L-4.76837e-07 10L5.55 5.88889Z"
style={{ fill: 'var(--affine-tooltip)' }}
/>
</svg>
</>
) : placement.indexOf('right') === 0 ? (
<>
<svg
xmlns="http://www.w3.org/2000/svg"
width="6"
height="10"
viewBox="0 0 6 10"
style={{ fill: 'var(--affine-tooltip)' }}
>
<path
d="M0.45 4.11111C-0.15 4.55556 -0.15 5.44445 0.45 5.88889L6 10V0L0.45 4.11111Z"
style={{ fill: 'var(--affine-tooltip)' }}
/>
</svg>
{content}
</>
) : (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
{content}
<svg
xmlns="http://www.w3.org/2000/svg"
width="11"
height="6"
viewBox="0 0 11 6"
fill="none"
>
<path
d="M4.61111 5.55C5.05556 6.15 5.94445 6.15 6.38889 5.55L10.5 -4.76837e-07H0.5L4.61111 5.55Z"
style={{ fill: 'var(--affine-tooltip)' }}
/>
</svg>
</div>
)
) : (
content
)}
</div>
</Grow>
)}
</BasicStyledPopper>
)}
</Container>
</ClickAwayListener>
);
};
// The children of ClickAwayListener must be a DOM Node to judge whether the click is outside, use node.contains
const Container = styled('div')({
display: 'contents',
});
export const BasicStyledPopper = styled(PopperUnstyled, {
shouldForwardProp: (propName: string) =>
!['zIndex'].some(name => name === propName),
})<{
zIndex?: CSSProperties['zIndex'];
}>(({ zIndex }) => {
return {
zIndex: zIndex ?? 'var(--affine-z-index-popover)',
};
});

View File

@@ -1,66 +0,0 @@
import type { PopperProps as PopperUnstyledProps } from '@mui/base/Popper';
import Grow from '@mui/material/Grow';
import type { CSSProperties, PropsWithChildren } from 'react';
import { useState } from 'react';
import { PopperArrow } from './popover-arrow';
import { BasicStyledPopper } from './popper';
import { PopperWrapper } from './styles';
export type PurePopperProps = {
zIndex?: CSSProperties['zIndex'];
offset?: [number, number];
showArrow?: boolean;
} & PopperUnstyledProps &
PropsWithChildren;
export const PurePopper = (props: PurePopperProps) => {
const {
children,
zIndex,
offset,
showArrow = false,
modifiers = [],
placement,
...otherProps
} = props;
const [arrowRef, setArrowRef] = useState<HTMLElement | null>();
return (
<BasicStyledPopper
zIndex={zIndex}
transition
modifiers={[
{
name: 'offset',
options: {
offset,
},
},
{
name: 'arrow',
enabled: showArrow,
options: {
element: arrowRef,
},
},
...modifiers,
]}
placement={placement}
{...otherProps}
>
{({ TransitionProps }) => (
<Grow {...TransitionProps}>
<PopperWrapper>
{showArrow && (
<PopperArrow placement={placement} ref={setArrowRef} />
)}
{children}
</PopperWrapper>
</Grow>
)}
</BasicStyledPopper>
);
};

View File

@@ -1,7 +0,0 @@
import { styled } from '../../styles';
export const PopperWrapper = styled('div')(() => {
return {
position: 'relative',
};
});

View File

@@ -1,57 +0,0 @@
import type { PopperPlacementType } from '@mui/material';
import { styled } from '../../styles';
export type PopperDirection =
| 'none'
| 'left-top'
| 'left-bottom'
| 'right-top'
| 'right-bottom';
const getBorderRadius = (direction: PopperDirection, radius = '0') => {
const map: Record<PopperDirection, string> = {
none: `${radius}`,
'left-top': `0 ${radius} ${radius} ${radius}`,
'left-bottom': `${radius} ${radius} ${radius} 0`,
'right-top': `${radius} 0 ${radius} ${radius}`,
'right-bottom': `${radius} ${radius} 0 ${radius}`,
};
return map[direction];
};
export const placementToContainerDirection: Record<
PopperPlacementType,
PopperDirection
> = {
top: 'none',
'top-start': 'left-bottom',
'top-end': 'right-bottom',
right: 'none',
'right-start': 'left-top',
'right-end': 'left-bottom',
bottom: 'none',
'bottom-start': 'none',
'bottom-end': 'none',
left: 'none',
'left-start': 'right-top',
'left-end': 'right-bottom',
auto: 'none',
'auto-start': 'none',
'auto-end': 'none',
};
export const StyledPopperContainer = styled('div')<{
placement?: PopperPlacementType;
}>(({ placement = 'top' }) => {
const direction = placementToContainerDirection[placement];
const borderRadius = getBorderRadius(
direction,
'var(--affine-popover-radius)'
);
return {
borderRadius,
};
});
export default StyledPopperContainer;

View File

@@ -0,0 +1,94 @@
import { keyframes, style } from '@vanilla-extract/css';
import type { PickStringFromUnion, SkeletonProps } from './types';
// variables
const bg = 'var(--affine-placeholder-color)';
const highlight = 'rgba(255, 255, 255, 0.4)';
const defaultHeight = '32px';
const pulseKeyframes = keyframes({
'0%': { opacity: 1 },
'50%': { opacity: 0.5 },
'100%': { opacity: 1 },
});
const waveKeyframes = keyframes({
'0%': { transform: 'translateX(-100%)' },
'50%': { transform: 'translateX(100%)' },
'100%': { transform: 'translateX(100%)' },
});
export const root = style({
display: 'block',
width: '100%',
height: defaultHeight,
flexShrink: 0,
/**
* paint background in ::before,
* so that we can use opacity to control the color
**/
position: 'relative',
'::before': {
content: '',
position: 'absolute',
borderRadius: 'inherit',
inset: 0,
opacity: 0.3,
backgroundColor: bg,
},
});
export const variant: Record<string, string> = {
circular: style({
width: defaultHeight,
borderRadius: '50%',
}),
rectangular: style({
borderRadius: '0px',
}),
rounded: style({
borderRadius: '8px',
}),
text: style({
borderRadius: '4px',
height: '1.2em',
marginTop: '0.2em',
marginBottom: '0.2em',
}),
};
export const animation: Record<
PickStringFromUnion<SkeletonProps['animation']>,
string
> = {
pulse: style({
animation: `${pulseKeyframes} 2s ease-in-out 0.5s infinite`,
}),
wave: style({
position: 'relative',
overflow: 'hidden',
/* Fix bug in Safari https://bugs.webkit.org/show_bug.cgi?id=68196 */
WebkitMaskImage: '-webkit-radial-gradient(white, black)',
'::after': {
animation: `${waveKeyframes} 2s linear 0.5s infinite`,
background: `linear-gradient(
90deg,
transparent,
${highlight},
transparent
)`,
content: '',
position: 'absolute',
transform:
'translateX(-100%)' /* Avoid flash during server-side hydration */,
bottom: 0,
left: 0,
right: 0,
top: 0,
},
}),
};

View File

@@ -0,0 +1,2 @@
export * from './skeleton';
export * from './types';

View File

@@ -0,0 +1,49 @@
import clsx from 'clsx';
import * as styles from './index.css';
import type { SkeletonProps } from './types';
function getSize(size: number | string) {
return typeof size === 'number' || /^\d+$/.test(size) ? `${size}px` : size;
}
/**
*
* @returns
*/
export const Skeleton = ({
animation = 'pulse',
variant = 'text',
children,
width: _width,
height: _height,
style: _style,
className: _className,
...props
}: SkeletonProps) => {
const width = _width !== undefined ? getSize(_width) : undefined;
const height = _height !== undefined ? getSize(_height) : undefined;
const style = {
width,
height,
...(_style || {}),
};
return (
<div
className={clsx(
_className,
styles.root,
styles.variant[variant],
animation && styles.animation[animation]
)}
style={style}
{...props}
>
{children}
</div>
);
};

View File

@@ -0,0 +1,33 @@
import type { HTMLAttributes, PropsWithChildren } from 'react';
export interface SkeletonProps
extends PropsWithChildren,
HTMLAttributes<HTMLElement> {
/**
* The animation. If `false` the animation effect is disabled.
*/
animation?: 'pulse' | 'wave' | false;
/**
* The type of content that will be rendered.
* @default `'text'`
*/
variant?: 'circular' | 'rectangular' | 'rounded' | 'text' | string;
/**
* Width of the skeleton. Useful when the skeleton is inside an inline element with no width of its own.
*/
width?: number | string;
/**
* Height of the skeleton. Useful when you don't want to adapt the skeleton to a text element but for instance a card.
*/
height?: number | string;
/**
* Wrapper component. If not provided, the default element is a div.
*/
wrapper?: string;
}
export type PickStringFromUnion<T> = T extends string ? T : never;

View File

@@ -1,10 +1,3 @@
// import Table from '@mui/material/Table';
// import TableBody from '@mui/material/TableBody';
// import TableCell from '@mui/material/TableCell';
// import TableHead from '@mui/material/TableHead';
// import TableRow from '@mui/material/TableRow';
//
export * from './interface'; export * from './interface';
export * from './table'; export * from './table';
export * from './table-body'; export * from './table-body';

View File

@@ -1,32 +0,0 @@
import { useState } from 'react';
import type { TreeNodeProps } from '../types';
export const useCollapsed = ({
initialCollapsedIds = [],
disableCollapse = false,
}: {
disableCollapse?: boolean;
initialCollapsedIds?: string[];
}) => {
// TODO: should record collapsedIds in localStorage
const [collapsedIds, setCollapsedIds] =
useState<string[]>(initialCollapsedIds);
const setCollapsed: TreeNodeProps['setCollapsed'] = (id, collapsed) => {
if (disableCollapse) {
return;
}
if (collapsed) {
setCollapsedIds(ids => [...ids, id]);
} else {
setCollapsedIds(ids => ids.filter(i => i !== id));
}
};
return {
collapsedIds,
setCollapsed,
};
};
export default useCollapsed;

View File

@@ -1,63 +0,0 @@
import { useEffect, useState } from 'react';
import type { TreeViewProps } from '../types';
import { flattenIds } from '../utils';
export const useSelectWithKeyboard = <RenderProps>({
data,
enableKeyboardSelection,
onSelect,
}: Pick<
TreeViewProps<RenderProps>,
'data' | 'enableKeyboardSelection' | 'onSelect'
>) => {
const [selectedId, setSelectedId] = useState<string>();
// TODO: should record collapsedIds in localStorage
useEffect(() => {
if (!enableKeyboardSelection) {
return;
}
const flattenedIds = flattenIds<RenderProps>(data);
const handleDirectionKeyDown = (e: KeyboardEvent) => {
if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') {
return;
}
if (selectedId === undefined) {
setSelectedId(flattenedIds[0]);
return;
}
let selectedIndex = flattenedIds.indexOf(selectedId);
if (e.key === 'ArrowDown') {
selectedIndex < flattenedIds.length - 1 && selectedIndex++;
}
if (e.key === 'ArrowUp') {
selectedIndex > 0 && selectedIndex--;
}
setSelectedId(flattenedIds[selectedIndex]);
};
const handleEnterKeyDown = (e: KeyboardEvent) => {
if (e.key !== 'Enter') {
return;
}
selectedId && onSelect?.(selectedId);
};
document.addEventListener('keydown', handleDirectionKeyDown);
document.addEventListener('keydown', handleEnterKeyDown);
return () => {
document.removeEventListener('keydown', handleDirectionKeyDown);
document.removeEventListener('keydown', handleEnterKeyDown);
};
}, [data, enableKeyboardSelection, onSelect, selectedId]);
return {
selectedId,
};
};
export default useSelectWithKeyboard;

View File

@@ -1,3 +0,0 @@
export * from './tree-node';
export * from './tree-view';
export * from './types';

View File

@@ -1,44 +0,0 @@
import MuiCollapse from '@mui/material/Collapse';
import { lightTheme } from '@toeverything/theme';
import type { CSSProperties } from 'react';
import { alpha, styled } from '../../styles';
export const StyledCollapse = styled(MuiCollapse)<{
indent?: CSSProperties['paddingLeft'];
}>(({ indent = 12 }) => {
return {
paddingLeft: indent,
};
});
export const StyledTreeNodeWrapper = styled('div')(() => {
return {
position: 'relative',
};
});
export const StyledTreeNodeContainer = styled('div')<{ isDragging?: boolean }>(
({ isDragging = false }) => {
return {
background: isDragging ? 'var(--affine-hover-color)' : '',
};
}
);
export const StyledNodeLine = styled('div')<{
isOver: boolean;
isTop?: boolean;
}>(({ isOver, isTop = false }) => {
return {
position: 'absolute',
left: '0',
...(isTop ? { top: '-1px' } : { bottom: '-1px' }),
width: '100%',
paddingTop: '2x',
borderTop: '2px solid',
borderColor: isOver ? 'var(--affine-primary-color)' : 'transparent',
boxShadow: isOver
? `0px 0px 8px ${alpha(lightTheme.primaryColor, 0.35)}`
: 'none',
zIndex: 1,
};
});

View File

@@ -1,88 +0,0 @@
import { useDroppable } from '@dnd-kit/core';
import { StyledNodeLine } from './styles';
import type { NodeLIneProps, TreeNodeItemProps } from './types';
export const NodeLine = <RenderProps,>({
node,
allowDrop = true,
isTop = false,
}: NodeLIneProps<RenderProps>) => {
const { isOver, setNodeRef } = useDroppable({
id: `${node.id}-${isTop ? 'top' : 'bottom'}-line`,
disabled: !allowDrop,
data: {
node,
position: {
topLine: isTop,
bottomLine: !isTop,
internal: false,
},
},
});
return (
<StyledNodeLine
ref={setNodeRef}
isOver={isOver && allowDrop}
isTop={isTop}
/>
);
};
export const TreeNodeItemWithDnd = <RenderProps,>({
node,
allowDrop,
setCollapsed,
...otherProps
}: TreeNodeItemProps<RenderProps>) => {
const { onAdd, onDelete } = otherProps;
const { isOver, setNodeRef } = useDroppable({
id: node.id,
disabled: !allowDrop,
data: {
node,
position: {
topLine: false,
bottomLine: false,
internal: true,
},
},
});
return (
<div ref={setNodeRef}>
<TreeNodeItem
onAdd={onAdd}
onDelete={onDelete}
node={node}
allowDrop={allowDrop}
setCollapsed={setCollapsed}
isOver={isOver}
{...otherProps}
/>
</div>
);
};
export const TreeNodeItem = <RenderProps,>({
node,
collapsed,
setCollapsed,
selectedId,
isOver = false,
onAdd,
onDelete,
disableCollapse,
allowDrop = true,
}: TreeNodeItemProps<RenderProps>) => {
return node.render?.(node, {
isOver: isOver && allowDrop,
onAdd: () => onAdd?.(node.id),
onDelete: () => onDelete?.(node.id),
collapsed,
setCollapsed,
isSelected: selectedId === node.id,
disableCollapse,
});
};

View File

@@ -1,106 +0,0 @@
import { useDraggable } from '@dnd-kit/core';
import { useMemo } from 'react';
import {
StyledCollapse,
StyledTreeNodeContainer,
StyledTreeNodeWrapper,
} from './styles';
import { NodeLine, TreeNodeItem, TreeNodeItemWithDnd } from './tree-node-inner';
import type { TreeNodeProps } from './types';
export const TreeNodeWithDnd = <RenderProps,>(
props: TreeNodeProps<RenderProps>
) => {
const { draggingId, node, allowDrop } = props;
const { attributes, listeners, setNodeRef } = useDraggable({
id: props.node.id,
});
const isDragging = useMemo(
() => draggingId === node.id,
[draggingId, node.id]
);
return (
<StyledTreeNodeContainer
ref={setNodeRef}
isDragging={isDragging}
{...listeners}
{...attributes}
>
<TreeNode
{...props}
allowDrop={allowDrop === false ? allowDrop : !isDragging}
/>
</StyledTreeNodeContainer>
);
};
export const TreeNode = <RenderProps,>({
node,
index,
allowDrop = true,
...otherProps
}: TreeNodeProps<RenderProps>) => {
const { indent, enableDnd, collapsedIds } = otherProps;
const collapsed = collapsedIds.includes(node.id);
const { renderTopLine = true, renderBottomLine = true } = node;
return (
<>
<StyledTreeNodeWrapper>
{enableDnd && renderTopLine && index === 0 && (
<NodeLine
node={node}
{...otherProps}
allowDrop={allowDrop}
isTop={true}
/>
)}
{enableDnd ? (
<TreeNodeItemWithDnd
node={node}
index={index}
allowDrop={allowDrop}
collapsed={collapsed}
{...otherProps}
/>
) : (
<TreeNodeItem
node={node}
index={index}
allowDrop={allowDrop}
collapsed={collapsed}
{...otherProps}
/>
)}
{enableDnd &&
renderBottomLine &&
(!node.children?.length || collapsed) && (
<NodeLine node={node} {...otherProps} allowDrop={allowDrop} />
)}
</StyledTreeNodeWrapper>
<StyledCollapse in={!collapsed} indent={indent}>
{node.children &&
node.children.map((childNode, index) =>
enableDnd ? (
<TreeNodeWithDnd
key={childNode.id}
node={childNode}
index={index}
{...otherProps}
allowDrop={allowDrop}
/>
) : (
<TreeNode
key={childNode.id}
node={childNode}
index={index}
allowDrop={false}
{...otherProps}
/>
)
)}
</StyledCollapse>
</>
);
};

View File

@@ -1,126 +0,0 @@
import type { DragEndEvent } from '@dnd-kit/core';
import {
closestCenter,
DndContext,
DragOverlay,
PointerSensor,
useSensor,
useSensors,
} from '@dnd-kit/core';
import { useCallback, useState } from 'react';
import useCollapsed from './hooks/use-collapsed';
import useSelectWithKeyboard from './hooks/use-select-with-keyboard';
import { TreeNode, TreeNodeWithDnd } from './tree-node';
import type { Node, TreeViewProps } from './types';
import { findNode } from './utils';
export const TreeView = <RenderProps,>({
data,
enableKeyboardSelection,
onSelect,
enableDnd = true,
disableCollapse,
onDrop,
...otherProps
}: TreeViewProps<RenderProps>) => {
const sensors = useSensors(
useSensor(PointerSensor, {
activationConstraint: {
distance: 8,
},
})
);
const { selectedId } = useSelectWithKeyboard({
data,
onSelect,
enableKeyboardSelection,
});
const { collapsedIds, setCollapsed } = useCollapsed({ disableCollapse });
const [draggingId, setDraggingId] = useState<string>();
const onDragEnd = useCallback(
(e: DragEndEvent) => {
const { active, over } = e;
const position = over?.data.current?.position;
const dropId = over?.data.current?.node.id;
setDraggingId(undefined);
if (!over || !active || !position) {
return;
}
onDrop?.(active.id as string, dropId, position);
},
[onDrop]
);
const onDragMove = useCallback((e: DragEndEvent) => {
setDraggingId(e.active.id as string);
}, []);
if (enableDnd) {
const treeNodes = data.map((node, index) => (
<TreeNodeWithDnd
key={node.id}
index={index}
collapsedIds={collapsedIds}
setCollapsed={setCollapsed}
node={node}
selectedId={selectedId}
enableDnd={enableDnd}
disableCollapse={disableCollapse}
draggingId={draggingId}
{...otherProps}
/>
));
const draggingNode = (function () {
let draggingNode: Node<RenderProps> | undefined;
if (draggingId) {
draggingNode = findNode(draggingId, data);
}
if (draggingNode) {
return (
<TreeNode
node={draggingNode}
index={0}
allowDrop={false}
collapsedIds={collapsedIds}
setCollapsed={() => {}}
{...otherProps}
/>
);
}
return null;
})();
return (
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragMove={onDragMove}
onDragEnd={onDragEnd}
>
{treeNodes}
<DragOverlay>{draggingNode}</DragOverlay>
</DndContext>
);
}
return (
<>
{data.map((node, index) => (
<TreeNode
key={node.id}
index={index}
collapsedIds={collapsedIds}
setCollapsed={setCollapsed}
node={node}
selectedId={selectedId}
enableDnd={enableDnd}
disableCollapse={disableCollapse}
{...otherProps}
/>
))}
</>
);
};
export default TreeView;

View File

@@ -1,72 +0,0 @@
import type { CSSProperties, ReactNode } from 'react';
export type DropPosition = {
topLine: boolean;
bottomLine: boolean;
internal: boolean;
};
export type OnDrop = (
dragId: string,
dropId: string,
position: DropPosition
) => void;
export type Node<RenderProps = unknown> = {
id: string;
children?: Node<RenderProps>[];
render: (
node: Node<RenderProps>,
eventsAndStatus: {
isOver: boolean;
onAdd: () => void;
onDelete: () => void;
collapsed: boolean;
setCollapsed: (id: string, collapsed: boolean) => void;
isSelected: boolean;
disableCollapse?: ReactNode;
},
renderProps?: RenderProps
) => ReactNode;
renderTopLine?: boolean;
renderBottomLine?: boolean;
};
type CommonProps = {
enableDnd?: boolean;
enableKeyboardSelection?: boolean;
indent?: CSSProperties['paddingLeft'];
onAdd?: (parentId: string) => void;
onDelete?: (deleteId: string) => void;
onDrop?: OnDrop;
// Only trigger when the enableKeyboardSelection is true
onSelect?: (id: string) => void;
disableCollapse?: ReactNode;
};
export type TreeNodeProps<RenderProps = unknown> = {
node: Node<RenderProps>;
index: number;
collapsedIds: string[];
setCollapsed: (id: string, collapsed: boolean) => void;
allowDrop?: boolean;
selectedId?: string;
draggingId?: string;
} & CommonProps;
export type TreeNodeItemProps<RenderProps = unknown> = {
collapsed: boolean;
setCollapsed: (id: string, collapsed: boolean) => void;
isOver?: boolean;
} & TreeNodeProps<RenderProps>;
export type TreeViewProps<RenderProps = unknown> = {
data: Node<RenderProps>[];
initialCollapsedIds?: string[];
disableCollapse?: boolean;
} & CommonProps;
export type NodeLIneProps<RenderProps = unknown> = {
allowDrop: boolean;
isTop?: boolean;
} & Pick<TreeNodeProps<RenderProps>, 'node'>;

View File

@@ -1,37 +0,0 @@
import type { Node } from './types';
export function flattenIds<RenderProps>(arr: Node<RenderProps>[]): string[] {
const result: string[] = [];
function flatten(arr: Node<RenderProps>[]) {
for (let i = 0, len = arr.length; i < len; i++) {
const item = arr[i];
result.push(item.id);
if (Array.isArray(item.children)) {
flatten(item.children);
}
}
}
flatten(arr);
return result;
}
export function findNode<RenderProps>(
id: string,
nodes: Node<RenderProps>[]
): Node<RenderProps> | undefined {
for (let i = 0, len = nodes.length; i < len; i++) {
const node = nodes[i];
if (node.id === id) {
return node;
}
if (node.children) {
const result = findNode(id, node.children);
if (result) {
return result;
}
}
}
return undefined;
}

View File

@@ -20,12 +20,6 @@ export const productionCacheGroups = {
priority: Number.MAX_SAFE_INTEGER, priority: Number.MAX_SAFE_INTEGER,
chunks: 'async' as const, chunks: 'async' as const,
}, },
mui: {
name: `npm-mui`,
test: testPackageName(/[\\/]node_modules[\\/](mui|@mui)[\\/]/),
priority: 200,
enforce: true,
},
blocksuite: { blocksuite: {
name: `npm-blocksuite`, name: `npm-blocksuite`,
test: testPackageName(/[\\/]node_modules[\\/](@blocksuite)[\\/]/), test: testPackageName(/[\\/]node_modules[\\/](@blocksuite)[\\/]/),

View File

@@ -40,7 +40,6 @@
"@emotion/server": "^11.11.0", "@emotion/server": "^11.11.0",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@marsidev/react-turnstile": "^0.3.1", "@marsidev/react-turnstile": "^0.3.1",
"@mui/material": "^5.14.14",
"@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-collapsible": "^1.0.3",
"@radix-ui/react-dialog": "^1.0.4", "@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-scroll-area": "^1.0.5",

View File

@@ -1,3 +1,4 @@
import { Skeleton } from '@affine/component';
import { Pagination } from '@affine/component/member-components'; import { Pagination } from '@affine/component/member-components';
import { import {
SettingHeader, SettingHeader,
@@ -19,7 +20,6 @@ import { Trans } from '@affine/i18n';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useMutation, useQuery } from '@affine/workspace/affine/gql'; import { useMutation, useQuery } from '@affine/workspace/affine/gql';
import { ArrowRightSmallIcon } from '@blocksuite/icons'; import { ArrowRightSmallIcon } from '@blocksuite/icons';
import { Skeleton } from '@mui/material';
import { Button, IconButton } from '@toeverything/components/button'; import { Button, IconButton } from '@toeverything/components/button';
import { Loading } from '@toeverything/components/loading'; import { Loading } from '@toeverything/components/loading';
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks'; import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';

View File

@@ -1,4 +1,4 @@
import { Skeleton } from '@mui/material'; import { Skeleton } from '@affine/component';
import { PlanLayout } from './layout'; import { PlanLayout } from './layout';
import * as styles from './skeleton.css'; import * as styles from './skeleton.css';

View File

@@ -1,10 +1,10 @@
import { MenuItem, PureMenu } from '@affine/component';
import { MuiClickAwayListener } from '@affine/component';
import type { SerializedBlock } from '@blocksuite/blocks'; import type { SerializedBlock } from '@blocksuite/blocks';
import type { BaseBlockModel } from '@blocksuite/store'; import type { BaseBlockModel } from '@blocksuite/store';
import type { Page } from '@blocksuite/store'; import type { Page } from '@blocksuite/store';
import type { VEditor } from '@blocksuite/virgo'; import type { VEditor } from '@blocksuite/virgo';
import { useCallback, useEffect, useMemo, useState } from 'react'; import { Menu, MenuItem } from '@toeverything/components/menu';
import { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
type ShortcutMap = { type ShortcutMap = {
[key: string]: (e: KeyboardEvent, page: Page) => void; [key: string]: (e: KeyboardEvent, page: Page) => void;
@@ -121,60 +121,6 @@ export type BookmarkProps = {
export const Bookmark = ({ page }: BookmarkProps) => { export const Bookmark = ({ page }: BookmarkProps) => {
const [anchor, setAnchor] = useState<Range | null>(null); const [anchor, setAnchor] = useState<Range | null>(null);
const [selectedOption, setSelectedOption] = useState<string>(
menuOptions[0].id
);
const shortcutMap = useMemo<ShortcutMap>(
() => ({
ArrowUp: () => {
const curIndex = menuOptions.findIndex(
({ id }) => id === selectedOption
);
if (menuOptions[curIndex - 1]) {
setSelectedOption(menuOptions[curIndex - 1].id);
} else if (curIndex === -1) {
setSelectedOption(menuOptions[0].id);
} else {
setSelectedOption(menuOptions[menuOptions.length - 1].id);
}
},
ArrowDown: () => {
const curIndex = menuOptions.findIndex(
({ id }) => id === selectedOption
);
if (curIndex !== -1 && menuOptions[curIndex + 1]) {
setSelectedOption(menuOptions[curIndex + 1].id);
} else {
setSelectedOption(menuOptions[0].id);
}
},
Enter: () =>
handleEnter({
page,
selectedOption,
callback: () => {
setAnchor(null);
},
}),
Escape: () => {
setAnchor(null);
},
}),
[page, selectedOption]
);
const onKeydown = useCallback(
(e: KeyboardEvent) => {
const shortcut = shortcutMap[e.key];
if (shortcut) {
e.stopPropagation();
e.preventDefault();
shortcut(e, page);
} else {
setAnchor(null);
}
},
[page, shortcutMap]
);
useEffect(() => { useEffect(() => {
const disposer = page.slots.pasted.on(pastedBlocks => { const disposer = page.slots.pasted.on(pastedBlocks => {
@@ -189,56 +135,35 @@ export const Bookmark = ({ page }: BookmarkProps) => {
return () => { return () => {
disposer.dispose(); disposer.dispose();
}; };
}, [onKeydown, page, shortcutMap]); }, [page]);
useEffect(() => { const portalContainer = anchor?.startContainer.parentElement;
if (anchor) {
document.addEventListener('keydown', onKeydown, { capture: true });
} else {
// reset status and remove event
setSelectedOption(menuOptions[0].id);
document.removeEventListener('keydown', onKeydown, { capture: true });
}
return () => { return anchor && portalContainer
document.removeEventListener('keydown', onKeydown, { capture: true }); ? createPortal(
}; <Menu
}, [anchor, onKeydown]); rootOptions={{
defaultOpen: true,
return anchor ? ( onOpenChange: (e: boolean) => !e && setAnchor(null),
<MuiClickAwayListener }}
onClickAway={() => { items={menuOptions.map(({ id, label }) => (
setAnchor(null); <MenuItem
setSelectedOption(''); key={id}
}} onClick={() =>
> handleEnter({
<div> page,
<PureMenu open={!!anchor} anchorEl={anchor} placement="bottom-start"> selectedOption: id,
{menuOptions.map(({ id, label }) => { callback: () => setAnchor(null),
return ( })
<MenuItem }
key={id} >
active={selectedOption === id} {label}
onClick={() => { </MenuItem>
handleEnter({ ))}
page, >
selectedOption: id, <span></span>
callback: () => { </Menu>,
setAnchor(null); portalContainer
}, )
}); : null;
}}
disableHover={true}
onMouseEnter={() => {
setSelectedOption(id);
}}
>
{label}
</MenuItem>
);
})}
</PureMenu>
</div>
</MuiClickAwayListener>
) : null;
}; };

View File

@@ -1,4 +1,3 @@
import { MuiFade } from '@affine/component';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { CloseIcon, NewIcon, UserGuideIcon } from '@blocksuite/icons'; import { CloseIcon, NewIcon, UserGuideIcon } from '@blocksuite/icons';
import { Tooltip } from '@toeverything/components/tooltip'; import { Tooltip } from '@toeverything/components/tooltip';
@@ -8,7 +7,7 @@ import { useCallback, useState } from 'react';
import { openOnboardingModalAtom, openSettingModalAtom } from '../../../atoms'; import { openOnboardingModalAtom, openSettingModalAtom } from '../../../atoms';
import { currentModeAtom } from '../../../atoms/mode'; import { currentModeAtom } from '../../../atoms/mode';
import { ShortcutsModal } from '../shortcuts-modal'; import type { SettingProps } from '../../affine/setting-modal';
import { ContactIcon, HelpIcon, KeyboardIcon } from './icons'; import { ContactIcon, HelpIcon, KeyboardIcon } from './icons';
import { import {
StyledAnimateWrapper, StyledAnimateWrapper,
@@ -36,113 +35,106 @@ export const HelpIsland = ({
const [spread, setShowSpread] = useState(false); const [spread, setShowSpread] = useState(false);
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const [openShortCut, setOpenShortCut] = useState(false); const openSettingModal = useCallback(
(tab: SettingProps['activeTab']) => {
setShowSpread(false);
const openAbout = useCallback(() => { setOpenSettingModalAtom({
setShowSpread(false); open: true,
activeTab: tab,
setOpenSettingModalAtom({ workspaceId: null,
open: true, });
activeTab: 'about', },
workspaceId: null, [setOpenSettingModalAtom]
}); );
}, [setOpenSettingModalAtom]); const openAbout = useCallback(
() => openSettingModal('about'),
[openSettingModal]
);
const openShortcuts = useCallback(
() => openSettingModal('shortcuts'),
[openSettingModal]
);
return ( return (
<> <StyledIsland
<StyledIsland spread={spread}
spread={spread} data-testid="help-island"
data-testid="help-island" onClick={() => {
onClick={() => { setShowSpread(!spread);
setShowSpread(!spread); }}
}} inEdgelessPage={mode === 'edgeless'}
inEdgelessPage={mode === 'edgeless'} >
<StyledAnimateWrapper
style={{ height: spread ? `${showList.length * 40 + 4}px` : 0 }}
> >
<StyledAnimateWrapper {showList.includes('whatNew') && (
style={{ height: spread ? `${showList.length * 40 + 4}px` : 0 }} <Tooltip content={t['com.affine.appUpdater.whatsNew']()} side="left">
> <StyledIconWrapper
{showList.includes('whatNew') && ( data-testid="right-bottom-change-log-icon"
<Tooltip onClick={() => {
content={t['com.affine.appUpdater.whatsNew']()} window.open(runtimeConfig.changelogUrl, '_blank');
side="left" }}
> >
<StyledIconWrapper <NewIcon />
data-testid="right-bottom-change-log-icon" </StyledIconWrapper>
onClick={() => { </Tooltip>
window.open(runtimeConfig.changelogUrl, '_blank'); )}
}} {showList.includes('contact') && (
> <Tooltip content={t['com.affine.helpIsland.contactUs']()} side="left">
<NewIcon /> <StyledIconWrapper
</StyledIconWrapper> data-testid="right-bottom-contact-us-icon"
</Tooltip> onClick={openAbout}
)}
{showList.includes('contact') && (
<Tooltip
content={t['com.affine.helpIsland.contactUs']()}
side="left"
> >
<StyledIconWrapper <ContactIcon />
data-testid="right-bottom-contact-us-icon" </StyledIconWrapper>
onClick={openAbout} </Tooltip>
> )}
<ContactIcon /> {showList.includes('shortcuts') && (
</StyledIconWrapper> <Tooltip
</Tooltip> content={t['com.affine.keyboardShortcuts.title']()}
)} side="left"
{showList.includes('shortcuts') && ( >
<Tooltip <StyledIconWrapper
content={t['com.affine.keyboardShortcuts.title']()} data-testid="shortcuts-icon"
side="left" onClick={openShortcuts}
> >
<StyledIconWrapper <KeyboardIcon />
data-testid="shortcuts-icon" </StyledIconWrapper>
onClick={() => { </Tooltip>
setShowSpread(false); )}
setOpenShortCut(true); {showList.includes('guide') && (
}} <Tooltip
> content={t['com.affine.helpIsland.gettingStarted']()}
<KeyboardIcon /> side="left"
</StyledIconWrapper> >
</Tooltip> <StyledIconWrapper
)} data-testid="easy-guide"
{showList.includes('guide') && ( onClick={() => {
<Tooltip setShowSpread(false);
content={t['com.affine.helpIsland.gettingStarted']()} setOpenOnboarding(true);
side="left" }}
> >
<StyledIconWrapper <UserGuideIcon />
data-testid="easy-guide" </StyledIconWrapper>
onClick={() => { </Tooltip>
setShowSpread(false); )}
setOpenOnboarding(true); </StyledAnimateWrapper>
}}
>
<UserGuideIcon />
</StyledIconWrapper>
</Tooltip>
)}
</StyledAnimateWrapper>
{spread ? (
<StyledTriggerWrapper spread>
<CloseIcon />
</StyledTriggerWrapper>
) : (
<Tooltip <Tooltip
content={t['com.affine.helpIsland.helpAndFeedback']()} content={t['com.affine.helpIsland.helpAndFeedback']()}
side="left" side="left"
> >
<MuiFade in={!spread} data-testid="faq-icon"> <StyledTriggerWrapper data-testid="faq-icon">
<StyledTriggerWrapper> <HelpIcon />
<HelpIcon />
</StyledTriggerWrapper>
</MuiFade>
</Tooltip>
<MuiFade in={spread}>
<StyledTriggerWrapper spread>
<CloseIcon />
</StyledTriggerWrapper> </StyledTriggerWrapper>
</MuiFade> </Tooltip>
</StyledIsland> )}
<ShortcutsModal </StyledIsland>
open={openShortCut}
onClose={() => setOpenShortCut(false)}
/>
</>
); );
}; };

View File

@@ -19,8 +19,8 @@ export const StyledIsland = styled('div')<{
? 'var(--affine-background-overlay-panel-color)' ? 'var(--affine-background-overlay-panel-color)'
: 'var(--affine-background-primary-color)', : 'var(--affine-background-primary-color)',
':hover': { ':hover': {
background: spread ? null : 'var(--affine-white)', background: spread ? undefined : 'var(--affine-white)',
boxShadow: spread ? null : 'var(--affine-menu-shadow)', boxShadow: spread ? undefined : 'var(--affine-menu-shadow)',
}, },
'::after': { '::after': {
content: '""', content: '""',
@@ -73,7 +73,7 @@ export const StyledTriggerWrapper = styled('div')<{
...displayFlex('center', 'center'), ...displayFlex('center', 'center'),
...positionAbsolute({ left: '4px', bottom: '4px' }), ...positionAbsolute({ left: '4px', bottom: '4px' }),
':hover': { ':hover': {
backgroundColor: spread ? 'var(--affine-hover-color)' : null, backgroundColor: spread ? 'var(--affine-hover-color)' : undefined,
}, },
}; };
}); });

View File

@@ -1,27 +0,0 @@
export const CloseIcon = () => {
return (
<svg
width="14"
height="14"
viewBox="0 0 14 14"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M7.94 7.00014L13.4667 1.47348C13.5759 1.34594 13.633 1.18189 13.6265 1.01411C13.62 0.846324 13.5504 0.687165 13.4317 0.568435C13.313 0.449706 13.1538 0.38015 12.986 0.37367C12.8183 0.367189 12.6542 0.42426 12.5267 0.533477L7 6.06014L1.47334 0.526811C1.3478 0.401275 1.17754 0.33075 1 0.33075C0.822468 0.33075 0.652205 0.401275 0.526669 0.526811C0.401133 0.652346 0.330608 0.82261 0.330608 1.00014C0.330608 1.17768 0.401133 1.34794 0.526669 1.47348L6.06 7.00014L0.526669 12.5268C0.456881 12.5866 0.400201 12.6601 0.360186 12.7428C0.32017 12.8255 0.297683 12.9156 0.294137 13.0074C0.290591 13.0993 0.306061 13.1908 0.339577 13.2764C0.373094 13.3619 0.423932 13.4396 0.488902 13.5046C0.553872 13.5695 0.63157 13.6204 0.71712 13.6539C0.80267 13.6874 0.894225 13.7029 0.986038 13.6993C1.07785 13.6958 1.16794 13.6733 1.25065 13.6333C1.33336 13.5933 1.4069 13.5366 1.46667 13.4668L7 7.94014L12.5267 13.4668C12.6542 13.576 12.8183 13.6331 12.986 13.6266C13.1538 13.6201 13.313 13.5506 13.4317 13.4319C13.5504 13.3131 13.62 13.154 13.6265 12.9862C13.633 12.8184 13.5759 12.6543 13.4667 12.5268L7.94 7.00014Z" />
</svg>
);
};
export const KeyboardIcon = () => {
return (
<svg
width="20"
height="15"
viewBox="0 0 20 15"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M17.745 0C18.3417 0 18.914 0.237053 19.336 0.65901C19.7579 1.08097 19.995 1.65326 19.995 2.25V11.755C19.995 12.3517 19.7579 12.924 19.336 13.346C18.914 13.7679 18.3417 14.005 17.745 14.005H2.25C1.95453 14.005 1.66194 13.9468 1.38896 13.8337C1.11598 13.7207 0.867941 13.5549 0.65901 13.346C0.450078 13.1371 0.284344 12.889 0.171271 12.616C0.058198 12.3431 0 12.0505 0 11.755V2.25C0 1.65326 0.237053 1.08097 0.65901 0.65901C1.08097 0.237053 1.65326 0 2.25 0H17.745ZM17.745 1.5H2.25C2.05109 1.5 1.86032 1.57902 1.71967 1.71967C1.57902 1.86032 1.5 2.05109 1.5 2.25V11.755C1.5 12.169 1.836 12.505 2.25 12.505H17.745C17.9439 12.505 18.1347 12.426 18.2753 12.2853C18.416 12.1447 18.495 11.9539 18.495 11.755V2.25C18.495 2.05109 18.416 1.86032 18.2753 1.71967C18.1347 1.57902 17.9439 1.5 17.745 1.5ZM4.75 9.5H15.25C15.44 9.50006 15.6229 9.57224 15.7618 9.70197C15.9006 9.8317 15.9851 10.0093 15.998 10.1989C16.011 10.3885 15.9515 10.5759 15.8316 10.7233C15.7117 10.8707 15.5402 10.9671 15.352 10.993L15.25 11H4.75C4.55998 10.9999 4.37706 10.9278 4.23821 10.798C4.09936 10.6683 4.01493 10.4907 4.00197 10.3011C3.98902 10.1115 4.04852 9.92411 4.16843 9.7767C4.28835 9.62929 4.45975 9.5329 4.648 9.507L4.75 9.5H15.25H4.75ZM14.5 6C14.7652 6 15.0196 6.10536 15.2071 6.29289C15.3946 6.48043 15.5 6.73478 15.5 7C15.5 7.26522 15.3946 7.51957 15.2071 7.70711C15.0196 7.89464 14.7652 8 14.5 8C14.2348 8 13.9804 7.89464 13.7929 7.70711C13.6054 7.51957 13.5 7.26522 13.5 7C13.5 6.73478 13.6054 6.48043 13.7929 6.29289C13.9804 6.10536 14.2348 6 14.5 6ZM8.505 6C8.77022 6 9.02457 6.10536 9.21211 6.29289C9.39964 6.48043 9.505 6.73478 9.505 7C9.505 7.26522 9.39964 7.51957 9.21211 7.70711C9.02457 7.89464 8.77022 8 8.505 8C8.23978 8 7.98543 7.89464 7.79789 7.70711C7.61036 7.51957 7.505 7.26522 7.505 7C7.505 6.73478 7.61036 6.48043 7.79789 6.29289C7.98543 6.10536 8.23978 6 8.505 6ZM5.505 6C5.77022 6 6.02457 6.10536 6.21211 6.29289C6.39964 6.48043 6.505 6.73478 6.505 7C6.505 7.26522 6.39964 7.51957 6.21211 7.70711C6.02457 7.89464 5.77022 8 5.505 8C5.23978 8 4.98543 7.89464 4.79789 7.70711C4.61036 7.51957 4.505 7.26522 4.505 7C4.505 6.73478 4.61036 6.48043 4.79789 6.29289C4.98543 6.10536 5.23978 6 5.505 6ZM11.505 6C11.7702 6 12.0246 6.10536 12.2121 6.29289C12.3996 6.48043 12.505 6.73478 12.505 7C12.505 7.26522 12.3996 7.51957 12.2121 7.70711C12.0246 7.89464 11.7702 8 11.505 8C11.2398 8 10.9854 7.89464 10.7979 7.70711C10.6104 7.51957 10.505 7.26522 10.505 7C10.505 6.73478 10.6104 6.48043 10.7979 6.29289C10.9854 6.10536 11.2398 6 11.505 6ZM4 3C4.26522 3 4.51957 3.10536 4.70711 3.29289C4.89464 3.48043 5 3.73478 5 4C5 4.26522 4.89464 4.51957 4.70711 4.70711C4.51957 4.89464 4.26522 5 4 5C3.73478 5 3.48043 4.89464 3.29289 4.70711C3.10536 4.51957 3 4.26522 3 4C3 3.73478 3.10536 3.48043 3.29289 3.29289C3.48043 3.10536 3.73478 3 4 3ZM6.995 3C7.26022 3 7.51457 3.10536 7.70211 3.29289C7.88964 3.48043 7.995 3.73478 7.995 4C7.995 4.26522 7.88964 4.51957 7.70211 4.70711C7.51457 4.89464 7.26022 5 6.995 5C6.72978 5 6.47543 4.89464 6.28789 4.70711C6.10036 4.51957 5.995 4.26522 5.995 4C5.995 3.73478 6.10036 3.48043 6.28789 3.29289C6.47543 3.10536 6.72978 3 6.995 3ZM9.995 3C10.2602 3 10.5146 3.10536 10.7021 3.29289C10.8896 3.48043 10.995 3.73478 10.995 4C10.995 4.26522 10.8896 4.51957 10.7021 4.70711C10.5146 4.89464 10.2602 5 9.995 5C9.72978 5 9.47543 4.89464 9.28789 4.70711C9.10036 4.51957 8.995 4.26522 8.995 4C8.995 3.73478 9.10036 3.48043 9.28789 3.29289C9.47543 3.10536 9.72978 3 9.995 3ZM12.995 3C13.2602 3 13.5146 3.10536 13.7021 3.29289C13.8896 3.48043 13.995 3.73478 13.995 4C13.995 4.26522 13.8896 4.51957 13.7021 4.70711C13.5146 4.89464 13.2602 5 12.995 5C12.7298 5 12.4754 4.89464 12.2879 4.70711C12.1004 4.51957 11.995 4.26522 11.995 4C11.995 3.73478 12.1004 3.48043 12.2879 3.29289C12.4754 3.10536 12.7298 3 12.995 3ZM15.995 3C16.2602 3 16.5146 3.10536 16.7021 3.29289C16.8896 3.48043 16.995 3.73478 16.995 4C16.995 4.26522 16.8896 4.51957 16.7021 4.70711C16.5146 4.89464 16.2602 5 15.995 5C15.7298 5 15.4754 4.89464 15.2879 4.70711C15.1004 4.51957 14.995 4.26522 14.995 4C14.995 3.73478 15.1004 3.48043 15.2879 3.29289C15.4754 3.10536 15.7298 3 15.995 3Z" />
</svg>
);
};

View File

@@ -1,97 +0,0 @@
import { MuiClickAwayListener, MuiSlide } from '@affine/component';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { CloseIcon } from '@blocksuite/icons';
import { IconButton } from '@toeverything/components/button';
import {
type ShortcutsInfo,
useEdgelessShortcuts,
useGeneralShortcuts,
useMarkdownShortcuts,
usePageShortcuts,
} from '../../../hooks/affine/use-shortcuts';
import { KeyboardIcon } from './icons';
import * as styles from './style.css';
type ModalProps = {
open: boolean;
onClose: () => void;
};
const ShortcutsPanel = ({
shortcutsInfo,
}: {
shortcutsInfo: ShortcutsInfo;
}) => {
return (
<>
<div className={styles.subtitle}>{shortcutsInfo.title}</div>
{Object.entries(shortcutsInfo.shortcuts).map(([title, shortcuts]) => {
return (
<div className={styles.listItem} key={title}>
<span>{title}</span>
<div className={styles.keyContainer}>
{shortcuts.map(key => {
return (
<span className={styles.key} key={key}>
{key}
</span>
);
})}
</div>
</div>
);
})}
</>
);
};
export const ShortcutsModal = ({ open, onClose }: ModalProps) => {
const t = useAFFiNEI18N();
const markdownShortcutsInfo = useMarkdownShortcuts();
const pageShortcutsInfo = usePageShortcuts();
const edgelessShortcutsInfo = useEdgelessShortcuts();
const generalShortcutsInfo = useGeneralShortcuts();
return (
<MuiSlide direction="left" in={open} mountOnEnter unmountOnExit>
<div className={styles.shortcutsModal} data-testid="shortcuts-modal">
<MuiClickAwayListener
onClickAway={() => {
onClose();
}}
>
<div>
<div
className={styles.modalHeader}
style={{ marginBottom: '-28px' }}
>
<div className={styles.title}>
<KeyboardIcon />
{t['Shortcuts']()}
</div>
<IconButton
style={{
position: 'absolute',
right: 6,
top: 6,
}}
onClick={() => {
onClose();
}}
icon={<CloseIcon />}
/>
</div>
<ShortcutsPanel shortcutsInfo={generalShortcutsInfo} />
<ShortcutsPanel shortcutsInfo={pageShortcutsInfo} />
<ShortcutsPanel shortcutsInfo={edgelessShortcutsInfo} />
<ShortcutsPanel shortcutsInfo={markdownShortcutsInfo} />
</div>
</MuiClickAwayListener>
</div>
</MuiSlide>
);
};

View File

@@ -1,89 +0,0 @@
import { globalStyle, style } from '@vanilla-extract/css';
export const shortcutsModal = style({
width: '288px',
height: '74vh',
paddingBottom: '28px',
backgroundColor: 'var(--affine-white)',
boxShadow: 'var(--affine-popover-shadow)',
borderRadius: `var(--affine-popover-radius)`,
overflow: 'auto',
position: 'fixed',
right: '12px',
top: '0',
bottom: '0',
margin: 'auto',
zIndex: 'var(--affine-z-index-modal)',
});
// export const shortcutsModal = style({
// color: 'var(--affine-text-primary-color)',
// fontWeight: '500',
// fontSize: 'var(--affine-font-sm)',
// height: '44px',
// display: 'flex',
// justifyContent: 'center',
// alignItems: 'center',
// svg: {
// width: '20px',
// marginRight: '14px',
// color: 'var(--affine-primary-color)',
// },
// });
export const title = style({
color: 'var(--affine-text-primary-color)',
fontWeight: '500',
fontSize: 'var(--affine-font-sm)',
height: '44px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
});
globalStyle(`${title} svg`, {
width: '20px',
marginRight: '14px',
color: 'var(--affine-primary-color)',
});
export const subtitle = style({
fontWeight: '500',
fontSize: 'var(--affine-font-sm)',
height: '34px',
lineHeight: '36px',
marginTop: '28px',
padding: '0 16px',
});
export const modalHeader = style({
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
paddingTop: '8px 4px 0 4px',
width: '100%',
padding: '8px 16px 0 16px',
position: 'sticky',
left: '0',
top: '0',
background: 'var(--affine-white)',
transition: 'background-color 0.5s',
});
export const listItem = style({
height: '34px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
fontSize: 'var(--affine-font-sm)',
padding: '0 16px',
});
export const keyContainer = style({
display: 'flex',
});
export const key = style({
selectors: {
'&:not(:last-child)::after': {
content: '+',
margin: '0 4px',
},
},
});

View File

@@ -1,130 +0,0 @@
import { alpha, displayFlex, styled, textEllipsis } from '@affine/component';
export const StyledListItem = styled('div')<{
active?: boolean;
disabled?: boolean;
}>(({ active, disabled }) => {
return {
height: '32px',
color: active
? 'var(--affine-primary-color)'
: 'var(--affine-text-primary-color)',
paddingLeft: '2px',
paddingRight: '2px',
borderRadius: '8px',
cursor: 'pointer',
marginBottom: '4px',
position: 'relative',
flexShrink: 0,
userSelect: 'none',
...displayFlex('flex-start', 'stretch'),
...(disabled
? {
cursor: 'not-allowed',
color: 'var(--affine-border-color)',
}
: {}),
'a > svg, div > svg': {
fontSize: '20px',
marginLeft: '14px',
marginRight: '12px',
color: active
? 'var(--affine-primary-color)'
: 'var(--affine-icon-color)',
},
':hover:not([disabled])': {
backgroundColor: 'var(--affine-hover-color)',
},
};
});
export const StyledCollapseButton = styled('button')<{
collapse: boolean;
show?: boolean;
}>(({ collapse, show = true }) => {
return {
width: '16px',
height: '100%',
...displayFlex('center', 'center'),
fontSize: '16px',
position: 'absolute',
left: '0',
top: '0',
bottom: '0',
margin: 'auto',
color: 'var(--affine-icon-color)',
opacity: '.6',
transition: 'opacity .15s ease-in-out',
display: show ? 'flex' : 'none',
svg: {
transform: `rotate(${collapse ? '0' : '-90'}deg)`,
},
':hover': {
opacity: '1',
},
':focus-visible': {
outline: '-webkit-focus-ring-color auto 1px',
},
};
});
export const StyledCollapseItem = styled('div')<{
disable?: boolean;
active?: boolean;
isOver?: boolean;
textWrap?: boolean;
}>(({ disable = false, active = false, isOver, textWrap = false }) => {
return {
width: '100%',
lineHeight: '1.5',
minHeight: '32px',
borderRadius: '8px',
...displayFlex('flex-start', 'center'),
paddingRight: '2px',
position: 'relative',
color: disable
? 'var(--affine-text-disable-color)'
: active
? 'var(--affine-primary-color)'
: 'var(--affine-text-primary-color)',
cursor: disable ? 'not-allowed' : 'pointer',
background: isOver ? alpha('var(--affine-primary-color)', 0.06) : '',
userSelect: 'none',
...(textWrap
? {
wordBreak: 'break-word',
whiteSpace: 'pre-wrap',
}
: {}),
span: {
flexGrow: '1',
textAlign: 'left',
...textEllipsis(1),
},
'> svg': {
fontSize: '20px',
marginRight: '8px',
flexShrink: '0',
color: active
? 'var(--affine-primary-color)'
: 'var(--affine-icon-color)',
},
':hover': disable
? {}
: {
backgroundColor: 'var(--affine-hover-color)',
'.operation-button': {
visibility: 'visible',
},
},
};
});
export const StyledRouteNavigationWrapper = styled('div')({
height: '32px',
width: '80px',
marginRight: '16px',
...displayFlex('space-between', 'center'),
});

View File

@@ -1,85 +0,0 @@
import { displayFlex, styled, textEllipsis } from '@affine/component';
import { Link } from '@mui/material';
import { baseTheme } from '@toeverything/theme';
export const StyledSliderBarInnerWrapper = styled('div')(() => {
return {
flexGrow: 1,
margin: '0 2px',
position: 'relative',
height: 'calc(100% - 52px * 2)',
display: 'flex',
flexDirection: 'column',
};
});
export const StyledLink = styled(Link)(() => {
return {
flexGrow: 1,
textAlign: 'left',
color: 'inherit',
...displayFlex('flex-start', 'center'),
':visited': {
color: 'inherit',
},
overflow: 'hidden',
div: {
wordBreak: 'break-all',
wordWrap: 'break-word',
whiteSpace: 'nowrap',
...textEllipsis(1),
},
userDrag: 'none',
userSelect: 'none',
appRegion: 'no-drag',
WebkitUserSelect: 'none',
WebkitUserDrag: 'none',
WebkitAppRegion: 'no-drag',
};
});
export const StyledNewPageButton = styled('button')(() => {
return {
width: '100%',
height: '52px',
...displayFlex('flex-start', 'center'),
padding: '0 16px',
svg: {
fontSize: '20px',
color: 'var(--affine-icon-color)',
marginRight: '12px',
},
':hover': {
color: 'var(--affine-primary-color)',
svg: {
color: 'var(--affine-primary-color)',
},
},
};
});
export const StyledSliderModalBackground = styled('div')<{ active: boolean }>(({
active,
}) => {
return {
transition: 'opacity .15s',
pointerEvents: active ? 'auto' : 'none',
opacity: active ? 1 : 0,
position: 'fixed',
top: 0,
left: 0,
right: active ? 0 : '100%',
bottom: 0,
zIndex: parseInt(baseTheme.zIndexModal) - 1,
background: 'var(--affine-background-modal-color)',
};
});
export const StyledScrollWrapper = styled('div')<{
showTopBorder: boolean;
}>(({ showTopBorder }) => {
return {
maxHeight: '50%',
overflowY: 'auto',
borderTop: '1px solid',
borderColor: showTopBorder ? 'var(--affine-border-color)' : 'transparent',
};
});

View File

@@ -14,6 +14,10 @@ test('Open shortcuts modal', async ({ page }) => {
await shortcutsIcon.click(); await shortcutsIcon.click();
await page.waitForTimeout(1000); await page.waitForTimeout(1000);
const shortcutsModal = page.locator('[data-testid=shortcuts-modal]');
await expect(shortcutsModal).toContainText('Page'); const settingModal = page.getByTestId('setting-modal');
await expect(settingModal).toBeVisible();
const title = page.getByTestId('keyboard-shortcuts-title');
await expect(title).toBeVisible();
}); });

View File

@@ -9,7 +9,6 @@
"dependencies": { "dependencies": {
"@affine/component": "workspace:*", "@affine/component": "workspace:*",
"@affine/i18n": "workspace:*", "@affine/i18n": "workspace:*",
"@mui/material": "^5.14.14",
"@storybook/addon-actions": "^7.4.6", "@storybook/addon-actions": "^7.4.6",
"@storybook/addon-essentials": "^7.4.6", "@storybook/addon-essentials": "^7.4.6",
"@storybook/addon-interactions": "^7.4.6", "@storybook/addon-interactions": "^7.4.6",

View File

@@ -1,41 +0,0 @@
/* deepscan-disable USELESS_ARROW_FUNC_BIND */
import { Breadcrumbs } from '@affine/component';
import { Link, Typography } from '@mui/material';
import { expect } from '@storybook/jest';
import type { Meta, StoryFn } from '@storybook/react';
import { within } from '@storybook/testing-library';
export default {
title: 'AFFiNE/Breadcrumbs',
component: Breadcrumbs,
parameters: {
chromatic: { disableSnapshot: true },
},
} as Meta<typeof Breadcrumbs>;
const Template: StoryFn = args => <Breadcrumbs {...args} />;
export const Primary = Template.bind(undefined);
Primary.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
const text = canvas.getByText('AFFiNE');
expect(text.getAttribute('data-testid')).toBe('affine');
};
Primary.args = {
children: [
<Link
data-testid="affine"
key="1"
underline="hover"
color="inherit"
href="/"
>
AFFiNE
</Link>,
<Link key="2" underline="hover" color="inherit" href="/Docs/">
Docs
</Link>,
<Typography key="3" color="text.primary">
Introduction
</Typography>,
],
};

245
yarn.lock
View File

@@ -225,9 +225,6 @@ __metadata:
"@emotion/react": "npm:^11.11.1" "@emotion/react": "npm:^11.11.1"
"@emotion/server": "npm:^11.11.0" "@emotion/server": "npm:^11.11.0"
"@emotion/styled": "npm:^11.11.0" "@emotion/styled": "npm:^11.11.0"
"@mui/base": "npm:5.0.0-beta.19"
"@mui/icons-material": "npm:^5.14.14"
"@mui/material": "npm:^5.14.14"
"@popperjs/core": "npm:^2.11.8" "@popperjs/core": "npm:^2.11.8"
"@radix-ui/react-avatar": "npm:^1.0.4" "@radix-ui/react-avatar": "npm:^1.0.4"
"@radix-ui/react-collapsible": "npm:^1.0.3" "@radix-ui/react-collapsible": "npm:^1.0.3"
@@ -344,7 +341,6 @@ __metadata:
"@emotion/server": "npm:^11.11.0" "@emotion/server": "npm:^11.11.0"
"@emotion/styled": "npm:^11.11.0" "@emotion/styled": "npm:^11.11.0"
"@marsidev/react-turnstile": "npm:^0.3.1" "@marsidev/react-turnstile": "npm:^0.3.1"
"@mui/material": "npm:^5.14.14"
"@perfsee/webpack": "npm:^1.8.4" "@perfsee/webpack": "npm:^1.8.4"
"@pmmmwh/react-refresh-webpack-plugin": "npm:^0.5.11" "@pmmmwh/react-refresh-webpack-plugin": "npm:^0.5.11"
"@radix-ui/react-collapsible": "npm:^1.0.3" "@radix-ui/react-collapsible": "npm:^1.0.3"
@@ -821,7 +817,6 @@ __metadata:
"@blocksuite/lit": "npm:0.0.0-20231116023037-31273bb7-nightly" "@blocksuite/lit": "npm:0.0.0-20231116023037-31273bb7-nightly"
"@blocksuite/store": "npm:0.0.0-20231116023037-31273bb7-nightly" "@blocksuite/store": "npm:0.0.0-20231116023037-31273bb7-nightly"
"@dnd-kit/sortable": "npm:^7.0.2" "@dnd-kit/sortable": "npm:^7.0.2"
"@mui/material": "npm:^5.14.14"
"@storybook/addon-actions": "npm:^7.4.6" "@storybook/addon-actions": "npm:^7.4.6"
"@storybook/addon-essentials": "npm:^7.4.6" "@storybook/addon-essentials": "npm:^7.4.6"
"@storybook/addon-interactions": "npm:^7.4.6" "@storybook/addon-interactions": "npm:^7.4.6"
@@ -3455,7 +3450,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.23.1, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": "@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2":
version: 7.23.2 version: 7.23.2
resolution: "@babel/runtime@npm:7.23.2" resolution: "@babel/runtime@npm:7.23.2"
dependencies: dependencies:
@@ -5346,7 +5341,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@floating-ui/react-dom@npm:^2.0.0, @floating-ui/react-dom@npm:^2.0.2": "@floating-ui/react-dom@npm:^2.0.0":
version: 2.0.2 version: 2.0.2
resolution: "@floating-ui/react-dom@npm:2.0.2" resolution: "@floating-ui/react-dom@npm:2.0.2"
dependencies: dependencies:
@@ -6799,202 +6794,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/base@npm:5.0.0-beta.19":
version: 5.0.0-beta.19
resolution: "@mui/base@npm:5.0.0-beta.19"
dependencies:
"@babel/runtime": "npm:^7.23.1"
"@floating-ui/react-dom": "npm:^2.0.2"
"@mui/types": "npm:^7.2.6"
"@mui/utils": "npm:^5.14.13"
"@popperjs/core": "npm:^2.11.8"
clsx: "npm:^2.0.0"
prop-types: "npm:^15.8.1"
peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@types/react":
optional: true
checksum: 4ed42c07aa2da31449c337da8535ab38068e1613e85fc69d4b8d60a1d3a270431c32cf0a9e753ae5d11cf4ea197221acda9fd7ad1f93992edc22c7c170a334f4
languageName: node
linkType: hard
"@mui/base@npm:5.0.0-beta.20":
version: 5.0.0-beta.20
resolution: "@mui/base@npm:5.0.0-beta.20"
dependencies:
"@babel/runtime": "npm:^7.23.1"
"@floating-ui/react-dom": "npm:^2.0.2"
"@mui/types": "npm:^7.2.6"
"@mui/utils": "npm:^5.14.13"
"@popperjs/core": "npm:^2.11.8"
clsx: "npm:^2.0.0"
prop-types: "npm:^15.8.1"
peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@types/react":
optional: true
checksum: 5926ae342f2a95a73a8ec3cf5fd9d4d8920b3c8f1faaa396349bd1d16f95e2f6639f049a7838a536d02a1d7a6f805378c0a6c384ad18c33c6eb3c00f50011905
languageName: node
linkType: hard
"@mui/core-downloads-tracker@npm:^5.14.14":
version: 5.14.14
resolution: "@mui/core-downloads-tracker@npm:5.14.14"
checksum: 93a1f16141e3ef4ef63985079dabf6b6196b8f7581f2d71338fca5c00e5834bcecb65ee0ad6a20fc61bbdce33a55b3f02d18c37e1c9937106d65d67b6fa25acd
languageName: node
linkType: hard
"@mui/icons-material@npm:^5.14.14":
version: 5.14.14
resolution: "@mui/icons-material@npm:5.14.14"
dependencies:
"@babel/runtime": "npm:^7.23.1"
peerDependencies:
"@mui/material": ^5.0.0
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@types/react":
optional: true
checksum: a5ea6d8942f25f1389ac8921e9f960fd38e793b9851e8d5bf535a8b342be4c9f081f62390891636570495a0d6f4bd69fc6fea80a0b76efee7ee4b29627af16a4
languageName: node
linkType: hard
"@mui/material@npm:^5.14.14":
version: 5.14.14
resolution: "@mui/material@npm:5.14.14"
dependencies:
"@babel/runtime": "npm:^7.23.1"
"@mui/base": "npm:5.0.0-beta.20"
"@mui/core-downloads-tracker": "npm:^5.14.14"
"@mui/system": "npm:^5.14.14"
"@mui/types": "npm:^7.2.6"
"@mui/utils": "npm:^5.14.13"
"@types/react-transition-group": "npm:^4.4.7"
clsx: "npm:^2.0.0"
csstype: "npm:^3.1.2"
prop-types: "npm:^15.8.1"
react-is: "npm:^18.2.0"
react-transition-group: "npm:^4.4.5"
peerDependencies:
"@emotion/react": ^11.5.0
"@emotion/styled": ^11.3.0
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@emotion/react":
optional: true
"@emotion/styled":
optional: true
"@types/react":
optional: true
checksum: 637ad369efb4b5173ca6dc267fb865fe267b9d90c09721ac3084ce5a4b61d1f9ae658b5352b877faff335299f2a7cdbe70155c2870fd50f37209b3a0b0482550
languageName: node
linkType: hard
"@mui/private-theming@npm:^5.14.14":
version: 5.14.14
resolution: "@mui/private-theming@npm:5.14.14"
dependencies:
"@babel/runtime": "npm:^7.23.1"
"@mui/utils": "npm:^5.14.13"
prop-types: "npm:^15.8.1"
peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@types/react":
optional: true
checksum: 23fc5a901ea655d60fab30b5c85ea5f8e62e6813f3d89f648f94c8da9437787554adc1a997bf0dc81890a4b706062d43652f9bdbbaddab0c23ef35d6ee07d4e9
languageName: node
linkType: hard
"@mui/styled-engine@npm:^5.14.13":
version: 5.14.13
resolution: "@mui/styled-engine@npm:5.14.13"
dependencies:
"@babel/runtime": "npm:^7.23.1"
"@emotion/cache": "npm:^11.11.0"
csstype: "npm:^3.1.2"
prop-types: "npm:^15.8.1"
peerDependencies:
"@emotion/react": ^11.4.1
"@emotion/styled": ^11.3.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@emotion/react":
optional: true
"@emotion/styled":
optional: true
checksum: 0ac6efb025d2e2d3d288c83e55dd152c9d42bb3521dc9c225dc78be37228f023853c19558141d650b4104b2099ba31a5680df0fc32ca9b24463c3ab4e4a83ada
languageName: node
linkType: hard
"@mui/system@npm:^5.14.14":
version: 5.14.14
resolution: "@mui/system@npm:5.14.14"
dependencies:
"@babel/runtime": "npm:^7.23.1"
"@mui/private-theming": "npm:^5.14.14"
"@mui/styled-engine": "npm:^5.14.13"
"@mui/types": "npm:^7.2.6"
"@mui/utils": "npm:^5.14.13"
clsx: "npm:^2.0.0"
csstype: "npm:^3.1.2"
prop-types: "npm:^15.8.1"
peerDependencies:
"@emotion/react": ^11.5.0
"@emotion/styled": ^11.3.0
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@emotion/react":
optional: true
"@emotion/styled":
optional: true
"@types/react":
optional: true
checksum: f748caa2572e86f97950ddd182907c1d434440c17b64aefdde935eeed7cb59dc77b42a1a8ca17e554b74cb6b87422efb2e16101bf4cdac78404c9ba5a2971cbf
languageName: node
linkType: hard
"@mui/types@npm:^7.2.6":
version: 7.2.6
resolution: "@mui/types@npm:7.2.6"
peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@types/react":
optional: true
checksum: 3701cac48e14150a4dfbf6ebdcd59bf93f3b8c9b7b35aeb81737e6802cb98a41daa374596ba09a66756fc78d838fc5b4f4b748e6d0d35ebdcf86f14da952ef68
languageName: node
linkType: hard
"@mui/utils@npm:^5.14.13":
version: 5.14.13
resolution: "@mui/utils@npm:5.14.13"
dependencies:
"@babel/runtime": "npm:^7.23.1"
"@types/prop-types": "npm:^15.7.7"
prop-types: "npm:^15.8.1"
react-is: "npm:^18.2.0"
peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@types/react":
optional: true
checksum: 461dd7f9a3bf9c469aca32ca95b1806cc26cd6a00c90539ebede4555e80a14209f47c7026ddc46712f135ea9139abdf1b5c91d980a463b15f3ac10a1fef85339
languageName: node
linkType: hard
"@napi-rs/cli@npm:^2.16.3": "@napi-rs/cli@npm:^2.16.3":
version: 2.16.3 version: 2.16.3
resolution: "@napi-rs/cli@npm:2.16.3" resolution: "@napi-rs/cli@npm:2.16.3"
@@ -13608,7 +13407,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/prop-types@npm:*, @types/prop-types@npm:^15.7.7": "@types/prop-types@npm:*":
version: 15.7.8 version: 15.7.8
resolution: "@types/prop-types@npm:15.7.8" resolution: "@types/prop-types@npm:15.7.8"
checksum: 61dfad79da8b1081c450bab83b77935df487ae1cdd4660ec7df6be8e74725c15fa45cf486ce057addc956ca4ae78300b97091e2a25061133d1b9a1440bc896ae checksum: 61dfad79da8b1081c450bab83b77935df487ae1cdd4660ec7df6be8e74725c15fa45cf486ce057addc956ca4ae78300b97091e2a25061133d1b9a1440bc896ae
@@ -13659,15 +13458,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/react-transition-group@npm:^4.4.7":
version: 4.4.7
resolution: "@types/react-transition-group@npm:4.4.7"
dependencies:
"@types/react": "npm:*"
checksum: 7bbd52516c79d5a0b621366115c161a625293c179c1c44f02301634f3f6aab32c0c484e8f109d0d1e20d158ed471aaaf3140b26c21dc52398c335fc0981027a0
languageName: node
linkType: hard
"@types/react@npm:*, @types/react@npm:>=16, @types/react@npm:^18.2.28": "@types/react@npm:*, @types/react@npm:>=16, @types/react@npm:^18.2.28":
version: 18.2.28 version: 18.2.28
resolution: "@types/react@npm:18.2.28" resolution: "@types/react@npm:18.2.28"
@@ -18107,7 +17897,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"csstype@npm:^3.0.10, csstype@npm:^3.0.2, csstype@npm:^3.0.7, csstype@npm:^3.1.1, csstype@npm:^3.1.2": "csstype@npm:^3.0.10, csstype@npm:^3.0.2, csstype@npm:^3.0.7, csstype@npm:^3.1.1":
version: 3.1.2 version: 3.1.2
resolution: "csstype@npm:3.1.2" resolution: "csstype@npm:3.1.2"
checksum: 1f39c541e9acd9562996d88bc9fb62d1cb234786ef11ed275567d4b2bd82e1ceacde25debc8de3d3b4871ae02c2933fa02614004c97190711caebad6347debc2 checksum: 1f39c541e9acd9562996d88bc9fb62d1cb234786ef11ed275567d4b2bd82e1ceacde25debc8de3d3b4871ae02c2933fa02614004c97190711caebad6347debc2
@@ -18893,16 +18683,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"dom-helpers@npm:^5.0.1":
version: 5.2.1
resolution: "dom-helpers@npm:5.2.1"
dependencies:
"@babel/runtime": "npm:^7.8.7"
csstype: "npm:^3.0.2"
checksum: bed2341adf8864bf932b3289c24f35fdd99930af77df46688abf2d753ff291df49a15850c874d686d9be6ec4e1c6835673906e64dbd8b2839d227f117a11fd41
languageName: node
linkType: hard
"dom-serializer@npm:0": "dom-serializer@npm:0":
version: 0.2.2 version: 0.2.2
resolution: "dom-serializer@npm:0.2.2" resolution: "dom-serializer@npm:0.2.2"
@@ -29997,7 +29777,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"prop-types@npm:^15, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": "prop-types@npm:^15, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
version: 15.8.1 version: 15.8.1
resolution: "prop-types@npm:15.8.1" resolution: "prop-types@npm:15.8.1"
dependencies: dependencies:
@@ -30712,21 +30492,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"react-transition-group@npm:^4.4.5":
version: 4.4.5
resolution: "react-transition-group@npm:4.4.5"
dependencies:
"@babel/runtime": "npm:^7.5.5"
dom-helpers: "npm:^5.0.1"
loose-envify: "npm:^1.4.0"
prop-types: "npm:^15.6.2"
peerDependencies:
react: ">=16.6.0"
react-dom: ">=16.6.0"
checksum: ca32d3fd2168c976c5d90a317f25d5f5cd723608b415fb3b9006f9d793c8965c619562d0884503a3e44e4b06efbca4fdd1520f30e58ca3e00a0890e637d55419
languageName: node
linkType: hard
"react-virtuoso@npm:^4.6.2": "react-virtuoso@npm:^4.6.2":
version: 4.6.2 version: 4.6.2
resolution: "react-virtuoso@npm:4.6.2" resolution: "react-virtuoso@npm:4.6.2"