mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-17 22:37:04 +08:00
refactor(core): remove all MUI related components and utilities (#4941)
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
@@ -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';
|
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
export * from './helper';
|
export * from './helper';
|
||||||
export * from './mui-theme';
|
export * from './styled';
|
||||||
export * from './mui-theme-provider';
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
import { alpha, css, keyframes, styled } from '@mui/material/styles';
|
|
||||||
|
|
||||||
export { alpha, css, keyframes, styled };
|
|
||||||
@@ -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);
|
|
||||||
3
packages/frontend/component/src/styles/styled.tsx
Normal file
3
packages/frontend/component/src/styles/styled.tsx
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
export { styled };
|
||||||
@@ -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;
|
|
||||||
@@ -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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -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?: {
|
||||||
|
|||||||
@@ -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';
|
|
||||||
@@ -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;
|
|
||||||
@@ -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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -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)',
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -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,
|
|
||||||
};
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export * from './interface';
|
|
||||||
export * from './popper';
|
|
||||||
export * from './pure-popper';
|
|
||||||
@@ -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'>;
|
|
||||||
@@ -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)'),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -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)',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import { styled } from '../../styles';
|
|
||||||
|
|
||||||
export const PopperWrapper = styled('div')(() => {
|
|
||||||
return {
|
|
||||||
position: 'relative',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -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;
|
|
||||||
94
packages/frontend/component/src/ui/skeleton/index.css.ts
Normal file
94
packages/frontend/component/src/ui/skeleton/index.css.ts
Normal 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,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
2
packages/frontend/component/src/ui/skeleton/index.ts
Normal file
2
packages/frontend/component/src/ui/skeleton/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './skeleton';
|
||||||
|
export * from './types';
|
||||||
49
packages/frontend/component/src/ui/skeleton/skeleton.tsx
Normal file
49
packages/frontend/component/src/ui/skeleton/skeleton.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
33
packages/frontend/component/src/ui/skeleton/types.ts
Normal file
33
packages/frontend/component/src/ui/skeleton/types.ts
Normal 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;
|
||||||
@@ -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';
|
||||||
|
|||||||
@@ -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;
|
|
||||||
@@ -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;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export * from './tree-node';
|
|
||||||
export * from './tree-view';
|
|
||||||
export * from './types';
|
|
||||||
@@ -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,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -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,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -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>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -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;
|
|
||||||
@@ -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'>;
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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)[\\/]/),
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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)}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -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',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -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'),
|
|
||||||
});
|
|
||||||
@@ -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',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -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();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
245
yarn.lock
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user