Skip to content

Commit

Permalink
✨ feat: Pref using react lazy
Browse files Browse the repository at this point in the history
The changes include implementing the `calcSize` function and the `ActionIcon` component. Additionally, the Suspense component is used for lazy loading and rendering of components asynchronously. Updates are made to EditableMessage, EmojiPicker, and Giscus components. Changes to imports and the addition of a new file called `calcSize.ts` are also included. The Icon, SearchBar, and Snippet components are updated to import the Spotlight component lazily.
  • Loading branch information
canisminor1990 committed Nov 17, 2023
1 parent 3512aef commit a5b3fc8
Show file tree
Hide file tree
Showing 11 changed files with 266 additions and 226 deletions.
39 changes: 39 additions & 0 deletions src/ActionIcon/calcSize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ActionIconSize } from '@/ActionIcon/index';

export const calcSize = (size?: ActionIconSize) => {
let blockSize: number;
let borderRadius: number;

switch (size) {
case 'large': {
blockSize = 44;
borderRadius = 8;
break;
}
case 'normal': {
blockSize = 36;
borderRadius = 5;
break;
}
case 'small': {
blockSize = 24;
borderRadius = 5;
break;
}
case 'site': {
blockSize = 34;
borderRadius = 5;
break;
}
default: {
blockSize = size?.blockSize || 36;
borderRadius = size?.borderRadius || 5;
break;
}
}

return {
blockSize,
borderRadius,
};
};
133 changes: 43 additions & 90 deletions src/ActionIcon/index.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,25 @@
import { Loader2 } from 'lucide-react';
import { forwardRef, useMemo } from 'react';
import { Suspense, forwardRef, lazy, useMemo } from 'react';

import Icon, { type IconProps } from '@/Icon';
import Spotlight from '@/Spotlight';
import Tooltip, { type TooltipProps } from '@/Tooltip';
import { DivProps } from '@/types';
import Icon, { type IconProps, type IconSizeConfig, type IconSizeType } from '@/Icon';
import type { TooltipProps } from '@/Tooltip';

import { calcSize } from './calcSize';
import { useStyles } from './style';

export type ActionIconSize =
| 'large'
| 'normal'
| 'small'
| 'site'
| {
blockSize?: number;
borderRadius?: number;
fontSize?: number;
strokeWidth?: number;
};
const Tooltip = lazy(() => import('@/Tooltip'));
const Spotlight = lazy(() => import('@/Spotlight'));

interface ActionIconSizeConfig extends IconSizeConfig {
blockSize?: number;
borderRadius?: number;
}

type ActionIconSizeType = 'site' | IconSizeType;

export type ActionIconSize = ActionIconSizeType | ActionIconSizeConfig;

const calcSize = (size?: ActionIconSize) => {
let blockSize: number;
let borderRadius: number;

switch (size) {
case 'large': {
blockSize = 44;
borderRadius = 8;
break;
}
case 'normal': {
blockSize = 36;
borderRadius = 5;
break;
}
case 'small': {
blockSize = 24;
borderRadius = 5;
break;
}
case 'site': {
blockSize = 34;
borderRadius = 5;
break;
}
default: {
blockSize = size?.blockSize || 36;
borderRadius = size?.borderRadius || 5;
break;
}
}

return {
blockSize,
borderRadius,
};
};

export interface ActionIconProps extends DivProps {
export interface ActionIconProps extends Omit<IconProps, 'size' | 'icon'> {
/**
* @description Whether the icon is active or not
* @default false
Expand All @@ -69,23 +30,16 @@ export interface ActionIconProps extends DivProps {
* @default false
*/
arrow?: boolean;
color?: IconProps['color'];
fill?: IconProps['fill'];
/**
* @description Glass blur style
* @default 'false'
*/
glass?: boolean;
/**
* @description The icon element to be rendered
* @type LucideIcon
*/
icon?: IconProps['icon'];
/**
* @description Set the loading status of ActionIcon
*/
loading?: boolean;

/**
* @description The position of the tooltip relative to the target
* @enum ["top","left","right","bottom","topLeft","topRight","bottomLeft","bottomRight","leftTop","leftBottom","rightTop","rightBottom"]
Expand Down Expand Up @@ -133,32 +87,28 @@ const ActionIcon = forwardRef<HTMLDivElement, ActionIconProps>(
children,
loading,
tooltipDelay = 0.5,
fillOpacity,
fillRule,
focusable,
...rest
},
ref,
) => {
const { styles, cx } = useStyles({ active: Boolean(active), glass: Boolean(glass) });

const { blockSize, borderRadius } = useMemo(() => calcSize(size), [size]);

const content = (
<>
{icon && (
<Icon
className={styles.icon}
color={color}
fill={fill}
icon={icon}
size={size === 'site' ? 'normal' : size}
/>
)}
{children}
</>
);
const iconProps = {
color,
fill,
fillOpacity,
fillRule,
focusable,
size: size === 'site' ? 'normal' : size,
};

const spin = (
<Icon color={color} icon={Loader2} size={size === 'site' ? 'normal' : size} spin />
);
const content = icon && <Icon className={styles.icon} icon={icon} {...iconProps} />;

const spin = <Icon icon={Loader2} {...iconProps} spin />;

const actionIconBlock = (
<div
Expand All @@ -168,23 +118,26 @@ const ActionIcon = forwardRef<HTMLDivElement, ActionIconProps>(
style={{ borderRadius, height: blockSize, width: blockSize, ...style }}
{...rest}
>
{spotlight && <Spotlight />}
<Suspense fallback={null}>{spotlight && <Spotlight />}</Suspense>
{loading ? spin : content}
{children}
</div>
);

if (!title) return actionIconBlock;

return (
<Tooltip
arrow={arrow}
mouseEnterDelay={tooltipDelay}
overlayStyle={{ pointerEvents: 'none' }}
placement={placement}
title={title}
>
{actionIconBlock}
</Tooltip>
<Suspense fallback={actionIconBlock}>
<Tooltip
arrow={arrow}
mouseEnterDelay={tooltipDelay}
overlayStyle={{ pointerEvents: 'none' }}
placement={placement}
title={title}
>
{actionIconBlock}
</Tooltip>
</Suspense>
);
},
);
Expand Down
15 changes: 10 additions & 5 deletions src/ChatItem/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { useResponsive } from 'antd-style';
import { memo } from 'react';
import { Suspense, lazy, memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import Actions from './components/Actions';
import Avatar from './components/Avatar';
import BorderSpacing from './components/BorderSpacing';
import ErrorContent from './components/ErrorContent';
import MessageContent from './components/MessageContent';
import Title from './components/Title';
import { useStyles } from './style';
import type { ChatItemProps } from './type';

const Actions = lazy(() => import('./components/Actions'));
const ErrorContent = lazy(() => import('./components/ErrorContent'));

const MOBILE_AVATAR_SIZE = 32;

const ChatItem = memo<ChatItemProps>(
Expand Down Expand Up @@ -81,7 +82,9 @@ const ChatItem = memo<ChatItemProps>(
gap={8}
>
{error ? (
<ErrorContent error={error} message={errorMessage} placement={placement} />
<Suspense fallback={null}>
<ErrorContent error={error} message={errorMessage} placement={placement} />
</Suspense>
) : (
<MessageContent
editing={editing}
Expand All @@ -97,7 +100,9 @@ const ChatItem = memo<ChatItemProps>(
type={type}
/>
)}
<Actions actions={actions} editing={editing} placement={placement} type={type} />
<Suspense fallback={null}>
<Actions actions={actions} editing={editing} placement={placement} type={type} />
</Suspense>
</Flexbox>
</Flexbox>
{mobile && type === 'block' && <BorderSpacing borderSpacing={MOBILE_AVATAR_SIZE} />}
Expand Down
79 changes: 43 additions & 36 deletions src/EditableMessage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { createStyles } from 'antd-style';
import { CSSProperties, memo } from 'react';
import { CSSProperties, Suspense, lazy, memo } from 'react';
import useControlledState from 'use-merge-value';

import Markdown from '@/Markdown';
import MessageInput, { type MessageInputProps } from '@/MessageInput';
import MessageModal, { type MessageModalProps } from '@/MessageModal';
import type { MessageInputProps } from '@/MessageInput';
import type { MessageModalProps } from '@/MessageModal';

const MessageInput = lazy(() => import('@/MessageInput'));
const MessageModal = lazy(() => import('@/MessageModal'));

const useStyles = createStyles(({ stylish }) => ({
markdown: stylish.markdownInChat,
Expand Down Expand Up @@ -114,23 +117,25 @@ const EditableMessage = memo<EditableMessageProps>(
const isAutoSize = height === 'auto';

const input = (
<MessageInput
className={classNames?.input}
classNames={{ textarea: classNames?.textarea }}
defaultValue={value}
editButtonSize={editButtonSize}
height={height}
onCancel={() => setTyping(false)}
onConfirm={(text) => {
onChange?.(text);
setTyping(false);
}}
placeholder={placeholder}
style={stylesProps?.input}
text={text}
textareaClassname={classNames?.input}
type={inputType}
/>
<Suspense fallback={null}>
<MessageInput
className={classNames?.input}
classNames={{ textarea: classNames?.textarea }}
defaultValue={value}
editButtonSize={editButtonSize}
height={height}
onCancel={() => setTyping(false)}
onConfirm={(text) => {
onChange?.(text);
setTyping(false);
}}
placeholder={placeholder}
style={stylesProps?.input}
text={text}
textareaClassname={classNames?.input}
type={inputType}
/>
</Suspense>
);

if (!value && showEditWhenEmpty) return input;
Expand All @@ -153,22 +158,24 @@ const EditableMessage = memo<EditableMessageProps>(
{value || placeholder}
</Markdown>
)}
<MessageModal
editing={isEdit}
extra={model?.extra}
footer={model?.footer}
height={height}
onChange={(text) => onChange?.(text)}
onEditingChange={setTyping}
onOpenChange={(e) => {
setExpand(e);
setTyping(false);
}}
open={expand}
placeholder={placeholder}
text={text}
value={value}
/>
<Suspense fallback={null}>
<MessageModal
editing={isEdit}
extra={model?.extra}
footer={model?.footer}
height={height}
onChange={(text) => onChange?.(text)}
onEditingChange={setTyping}
onOpenChange={(e) => {
setExpand(e);
setTyping(false);
}}
open={expand}
placeholder={placeholder}
text={text}
value={value}
/>
</Suspense>
</>
);
},
Expand Down
Loading

0 comments on commit a5b3fc8

Please sign in to comment.