Skip to content

Commit d190493

Browse files
✨ feat: Add Draw
1 parent abcf185 commit d190493

File tree

6 files changed

+252
-7
lines changed

6 files changed

+252
-7
lines changed

src/Draw/demos/index.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Draw, type DrawProps } from '@lobehub/ui';
2+
import { StoryBook, useControls, useCreateStore } from '@lobehub/ui/storybook';
3+
import { useRef } from 'react';
4+
5+
export default () => {
6+
const store = useCreateStore();
7+
const ref = useRef(null);
8+
const control: DrawProps | any = useControls(
9+
{
10+
containerMaxWidth: 1024,
11+
height: 600,
12+
noHeader: true,
13+
open: true,
14+
placement: {
15+
options: ['left', 'right', 'top', 'bottom'],
16+
value: 'bottom',
17+
},
18+
title: 'Drawer',
19+
},
20+
{ store },
21+
);
22+
23+
return (
24+
<StoryBook height={800} levaStore={store} noPadding ref={ref}>
25+
<Draw getContainer={false} sidebar={<div>sidebar</div>} {...control}>
26+
content
27+
</Draw>
28+
</StoryBook>
29+
);
30+
};

src/Draw/index.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
nav: Components
3+
group: Feedback
4+
title: Draw
5+
---
6+
7+
## Default
8+
9+
<code src="./demos/index.tsx" noPadding></code>
10+
11+
## APIs
12+
13+
<API></API>

src/Draw/index.tsx

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
'use client';
2+
3+
import { Drawer as AntdDraw, type DrawerProps as AntdDrawerProps } from 'antd';
4+
import { useTheme } from 'antd-style';
5+
import { XIcon } from 'lucide-react';
6+
import { CSSProperties, ReactNode, memo, useMemo } from 'react';
7+
import { Flexbox } from 'react-layout-kit';
8+
9+
import ActionIcon from '@/ActionIcon';
10+
11+
export interface DrawProps extends Omit<AntdDrawerProps, 'styles' | 'classNames'> {
12+
classNames?: AntdDrawerProps['classNames'] & {
13+
bodyContent?: string;
14+
extra?: string;
15+
title?: string;
16+
};
17+
containerMaxWidth?: number;
18+
noHeader?: boolean;
19+
sidebar?: ReactNode;
20+
sidebarWidth?: number;
21+
styles?: AntdDrawerProps['styles'] & {
22+
bodyContent?: CSSProperties;
23+
extra?: CSSProperties;
24+
title?: CSSProperties;
25+
};
26+
}
27+
28+
const Draw = memo<DrawProps>(
29+
({
30+
onClose,
31+
containerMaxWidth = 1024,
32+
classNames,
33+
title,
34+
placement,
35+
styles,
36+
children,
37+
height,
38+
width,
39+
extra,
40+
noHeader,
41+
sidebarWidth = 280,
42+
sidebar,
43+
...rest
44+
}) => {
45+
const theme = useTheme();
46+
47+
const headerBorder: CSSProperties = useMemo(() => {
48+
if (height === '100%' || width === '100%' || height === '100vh' || width === '100vw')
49+
return {};
50+
51+
switch (placement) {
52+
case 'top': {
53+
return {
54+
borderBottom: `1px solid ${theme.colorBorder}`,
55+
};
56+
}
57+
case 'bottom': {
58+
return {
59+
borderTop: `1px solid ${theme.colorBorder}`,
60+
};
61+
}
62+
case 'left': {
63+
return {
64+
borderRight: `1px solid ${theme.colorBorder}`,
65+
};
66+
}
67+
case 'right': {
68+
return {
69+
borderLeft: `1px solid ${theme.colorBorder}`,
70+
};
71+
}
72+
default: {
73+
return {};
74+
}
75+
}
76+
}, [placement, height, width, theme.colorBorder]);
77+
78+
const extraNode = (
79+
<Flexbox
80+
align={'center'}
81+
className={classNames?.extra}
82+
gap={4}
83+
horizontal
84+
justify={'flex-end'}
85+
style={{
86+
position: 'absolute',
87+
right: 4,
88+
top: 4,
89+
...styles?.extra,
90+
}}
91+
>
92+
{extra}
93+
<ActionIcon icon={XIcon} onClick={onClose} size={'site'} />
94+
</Flexbox>
95+
);
96+
97+
return (
98+
<AntdDraw
99+
classNames={classNames}
100+
closable={false}
101+
extra={noHeader ? undefined : extraNode}
102+
height={height}
103+
keyboard={true}
104+
onClose={onClose}
105+
placement={placement}
106+
styles={{
107+
...styles,
108+
body: {
109+
background: 'transparent',
110+
padding: '0 4px',
111+
...styles?.body,
112+
},
113+
content: {
114+
background: sidebar
115+
? `linear-gradient(to right, ${theme.colorBgContainer} 49.9%, ${theme.colorBgLayout} 50%)`
116+
: theme.colorBgContainer,
117+
...styles?.content,
118+
},
119+
header: {
120+
background: 'transparent',
121+
display: noHeader ? 'none' : undefined,
122+
padding: 4,
123+
...styles?.header,
124+
},
125+
wrapper: {
126+
background: theme.colorBgContainer,
127+
...headerBorder,
128+
...styles?.wrapper,
129+
},
130+
}}
131+
title={
132+
<Flexbox
133+
align={'center'}
134+
className={classNames?.title}
135+
horizontal
136+
justify={'flex-start'}
137+
paddingBlock={8}
138+
paddingInline={16}
139+
style={{
140+
justifySelf: 'center',
141+
maxWidth: containerMaxWidth,
142+
width: '100%',
143+
...styles?.title,
144+
}}
145+
>
146+
{title}
147+
</Flexbox>
148+
}
149+
width={width}
150+
{...rest}
151+
>
152+
<Flexbox
153+
className={classNames?.bodyContent}
154+
height={'100%'}
155+
horizontal={!!sidebar}
156+
paddingBlock={sidebar ? undefined : 12}
157+
paddingInline={sidebar ? undefined : 16}
158+
style={{
159+
justifySelf: 'center',
160+
maxWidth: containerMaxWidth,
161+
width: '100%',
162+
...styles?.bodyContent,
163+
}}
164+
>
165+
{noHeader && extraNode}
166+
{sidebar ? (
167+
<>
168+
<Flexbox
169+
paddingBlock={12}
170+
paddingInline={16}
171+
style={{
172+
background: theme.colorBgContainer,
173+
borderRight: `1px solid ${theme.colorBorderSecondary}`,
174+
height: '100%',
175+
}}
176+
width={sidebarWidth}
177+
>
178+
{sidebar}
179+
</Flexbox>
180+
<Flexbox
181+
flex={1}
182+
paddingBlock={12}
183+
paddingInline={16}
184+
style={{
185+
background: theme.colorBgLayout,
186+
height: '100%',
187+
}}
188+
>
189+
{children}
190+
</Flexbox>
191+
</>
192+
) : (
193+
children
194+
)}
195+
</Flexbox>
196+
</AntdDraw>
197+
);
198+
},
199+
);
200+
201+
export default Draw;

src/Hotkey/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ const Hotkey = memo<HotkeyProps>(
121121
<Flexbox
122122
align={'center'}
123123
className={cx(s, className)}
124-
gap={2}
124+
gap={isPure ? 6 : 2}
125125
horizontal
126126
style={{ visibility, ...style }}
127127
{...rest}

src/components.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export {
3030
default as DraggablePanelHeader,
3131
type DraggablePanelHeaderProps,
3232
} from './DraggablePanel/components/DraggablePanelHeader';
33+
export { default as Draw, type DrawProps } from './Draw';
3334
export { default as EditableText, type EditableTextProps } from './EditableText';
3435
export { default as EmojiPicker, type EmojiPickerProps } from './EmojiPicker';
3536
export { default as EmptyCard, type EmptyCardProps } from './EmptyCard';

src/storybook/StoryBook/index.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22

33
import { useResponsive } from 'antd-style';
44
import { LevaPanel } from 'leva';
5-
import { memo } from 'react';
6-
import { Flexbox } from 'react-layout-kit';
5+
import { forwardRef } from 'react';
6+
import { Flexbox, FlexboxProps } from 'react-layout-kit';
77

88
import DraggablePanel from '@/DraggablePanel';
9-
import { DivProps } from '@/types';
109

1110
import { useStyles } from './style';
1211

13-
export interface StoryBookProps extends DivProps {
12+
export interface StoryBookProps extends FlexboxProps {
1413
/**
1514
* @description The Leva store instance to be used by the component
1615
* @type levaStore
@@ -22,8 +21,8 @@ export interface StoryBookProps extends DivProps {
2221
noPadding?: boolean;
2322
}
2423

25-
export const StoryBook = memo<StoryBookProps>(
26-
({ levaStore, noPadding, className, children, ...rest }) => {
24+
export const StoryBook = forwardRef<HTMLDivElement, StoryBookProps>(
25+
({ levaStore, noPadding, className, children, ...rest }, ref) => {
2726
const { mobile } = useResponsive();
2827
const { styles, cx } = useStyles(Boolean(noPadding));
2928

@@ -33,6 +32,7 @@ export const StoryBook = memo<StoryBookProps>(
3332
className={cx(styles.editor, className)}
3433
horizontal={!mobile}
3534
justify={'stretch'}
35+
ref={ref}
3636
{...rest}
3737
>
3838
<Flexbox align={'center'} className={styles.left} flex={1} justify={'center'}>

0 commit comments

Comments
 (0)