Skip to content

Commit e9b14fc

Browse files
authoredOct 16, 2024··
feat: Sender support Sender.Header (#156)
* feat: support Sender.Header * chore: demo * docs: Semantic DOM * test: update snapshot * docs: update doc * docs: add closable
1 parent a7adab9 commit e9b14fc

File tree

17 files changed

+1720
-1064
lines changed

17 files changed

+1720
-1064
lines changed
 

‎.dumi/components/SemanticPreview.tsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ const useStyle = createStyles(({ token }, markPos: [number, number, number, numb
6767

6868
export interface SemanticPreviewProps {
6969
semantics: { name: string; desc: string; version?: string }[];
70-
children: React.ReactElement;
70+
children: React.ReactElement | ((injectProps: any) => React.ReactElement);
7171
height?: number;
7272
}
7373

@@ -91,9 +91,14 @@ const SemanticPreview: React.FC<SemanticPreviewProps> = (props) => {
9191
return classNames;
9292
}, [semantics]);
9393

94-
const cloneNode = React.cloneElement(children, {
94+
const injectProps = {
9595
classNames: semanticClassNames,
96-
});
96+
};
97+
98+
const cloneNode =
99+
typeof children === 'function'
100+
? children(injectProps)
101+
: React.cloneElement(children, injectProps);
97102

98103
// ======================== Hover =========================
99104
const containerRef = React.useRef<HTMLDivElement>(null);

‎components/sender/SenderHeader.tsx

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import { CloseOutlined } from '@ant-design/icons';
2+
import { Button } from 'antd';
3+
import classNames from 'classnames';
4+
import CSSMotion, { type MotionEventHandler } from 'rc-motion';
5+
import * as React from 'react';
6+
7+
export interface SendHeaderContextProps {
8+
prefixCls: string;
9+
}
10+
11+
export const SendHeaderContext = React.createContext<SendHeaderContextProps>({} as any);
12+
13+
export type SemanticType = 'header' | 'content';
14+
15+
export interface SenderHeaderProps {
16+
open?: boolean;
17+
onOpenChange?: (open: boolean) => void;
18+
title?: React.ReactNode;
19+
children?: React.ReactNode;
20+
className?: string;
21+
style?: React.CSSProperties;
22+
classNames?: Partial<Record<SemanticType, string>>;
23+
styles?: Partial<Record<SemanticType, React.CSSProperties>>;
24+
closable?: boolean;
25+
}
26+
27+
const collapseHeight: MotionEventHandler = () => ({
28+
height: 0,
29+
});
30+
const expandedHeight: MotionEventHandler = (ele) => ({
31+
height: ele.scrollHeight,
32+
});
33+
34+
export default function SenderHeader(props: SenderHeaderProps) {
35+
const {
36+
title,
37+
onOpenChange,
38+
open,
39+
children,
40+
className,
41+
style,
42+
classNames: classes = {},
43+
styles = {},
44+
closable,
45+
} = props;
46+
47+
const { prefixCls } = React.useContext(SendHeaderContext);
48+
49+
const headerCls = `${prefixCls}-header`;
50+
51+
return (
52+
<CSSMotion
53+
motionEnter
54+
motionLeave
55+
motionName={`${headerCls}-motion`}
56+
leavedClassName={`${headerCls}-motion-hidden`}
57+
onEnterStart={collapseHeight}
58+
onEnterActive={expandedHeight}
59+
onLeaveStart={expandedHeight}
60+
onLeaveActive={collapseHeight}
61+
visible={open}
62+
>
63+
{({ className: motionClassName, style: motionStyle }) => {
64+
return (
65+
<div
66+
className={classNames(headerCls, motionClassName, className)}
67+
style={{
68+
...motionStyle,
69+
...style,
70+
}}
71+
>
72+
{/* Header */}
73+
{closable !== false && (
74+
<div
75+
className={
76+
// We follow antd naming standard here.
77+
// So the header part is use `-header` suffix.
78+
// Though its little bit weird for double `-header`.
79+
classNames(`${headerCls}-header`, classes.header)
80+
}
81+
style={{
82+
...styles.header,
83+
}}
84+
>
85+
<div className={`${headerCls}-title`}>{title}</div>
86+
<div className={`${headerCls}-close`}>
87+
<Button
88+
type="text"
89+
icon={<CloseOutlined />}
90+
size="small"
91+
onClick={() => {
92+
onOpenChange?.(!open);
93+
}}
94+
/>
95+
</div>
96+
</div>
97+
)}
98+
99+
{/* Content */}
100+
{children && (
101+
<div
102+
className={classNames(`${headerCls}-content`, classes.content)}
103+
style={{
104+
...styles.content,
105+
}}
106+
>
107+
{children}
108+
</div>
109+
)}
110+
</div>
111+
);
112+
}}
113+
</CSSMotion>
114+
);
115+
}

‎components/sender/__tests__/__snapshots__/demo-extend.test.ts.snap

+512-381
Large diffs are not rendered by default.

‎components/sender/__tests__/__snapshots__/demo.test.ts.snap

+468-340
Large diffs are not rendered by default.

‎components/sender/__tests__/__snapshots__/index.test.tsx.snap

+91-83
Original file line numberDiff line numberDiff line change
@@ -5,69 +5,73 @@ exports[`Sender Component loading state 1`] = `
55
<div
66
class="ant-sender"
77
>
8-
<textarea
9-
class="ant-input ant-input-borderless ant-sender-input"
10-
readonly=""
11-
style="overflow-y: hidden; resize: none;"
12-
/>
138
<div
14-
class="ant-sender-actions-list"
9+
class="ant-sender-content"
1510
>
11+
<textarea
12+
class="ant-input ant-input-borderless ant-sender-input"
13+
readonly=""
14+
style="overflow-y: hidden; resize: none;"
15+
/>
1616
<div
17-
class="ant-sender-actions-list-presets ant-flex"
17+
class="ant-sender-actions-list"
1818
>
19-
<button
20-
class="ant-btn ant-btn-circle ant-btn-text ant-btn-color-primary ant-btn-variant-text ant-sender-actions-btn ant-sender-actions-btn-loading-button"
21-
type="button"
19+
<div
20+
class="ant-sender-actions-list-presets ant-flex"
2221
>
23-
<svg
24-
class="ant-sender-actions-btn-loading-icon"
25-
color="currentColor"
26-
viewBox="0 0 1000 1000"
27-
xmlns="http://www.w3.org/2000/svg"
28-
xmlns:xlink="http://www.w3.org/1999/xlink"
22+
<button
23+
class="ant-btn ant-btn-circle ant-btn-text ant-btn-color-primary ant-btn-variant-text ant-sender-actions-btn ant-sender-actions-btn-loading-button"
24+
type="button"
2925
>
30-
<title>
31-
Stop Loading
32-
</title>
33-
<rect
34-
fill="currentColor"
35-
height="250"
36-
rx="24"
37-
ry="24"
38-
width="250"
39-
x="375"
40-
y="375"
41-
/>
42-
<circle
43-
cx="500"
44-
cy="500"
45-
fill="none"
46-
opacity="0.45"
47-
r="450"
48-
stroke="currentColor"
49-
stroke-width="100"
50-
/>
51-
<circle
52-
cx="500"
53-
cy="500"
54-
fill="none"
55-
r="450"
56-
stroke="currentColor"
57-
stroke-dasharray="600 9999999"
58-
stroke-width="100"
26+
<svg
27+
class="ant-sender-actions-btn-loading-icon"
28+
color="currentColor"
29+
viewBox="0 0 1000 1000"
30+
xmlns="http://www.w3.org/2000/svg"
31+
xmlns:xlink="http://www.w3.org/1999/xlink"
5932
>
60-
<animatetransform
61-
attributeName="transform"
62-
dur="1s"
63-
from="0 500 500"
64-
repeatCount="indefinite"
65-
to="360 500 500"
66-
type="rotate"
33+
<title>
34+
Stop Loading
35+
</title>
36+
<rect
37+
fill="currentColor"
38+
height="250"
39+
rx="24"
40+
ry="24"
41+
width="250"
42+
x="375"
43+
y="375"
44+
/>
45+
<circle
46+
cx="500"
47+
cy="500"
48+
fill="none"
49+
opacity="0.45"
50+
r="450"
51+
stroke="currentColor"
52+
stroke-width="100"
6753
/>
68-
</circle>
69-
</svg>
70-
</button>
54+
<circle
55+
cx="500"
56+
cy="500"
57+
fill="none"
58+
r="450"
59+
stroke="currentColor"
60+
stroke-dasharray="600 9999999"
61+
stroke-width="100"
62+
>
63+
<animatetransform
64+
attributeName="transform"
65+
dur="1s"
66+
from="0 500 500"
67+
repeatCount="indefinite"
68+
to="360 500 500"
69+
type="rotate"
70+
/>
71+
</circle>
72+
</svg>
73+
</button>
74+
</div>
7175
</div>
7276
</div>
7377
</div>
@@ -78,44 +82,48 @@ exports[`Sender Component rtl render component should be rendered correctly in R
7882
<div
7983
class="ant-sender css-var-r1 ant-sender-rtl"
8084
>
81-
<textarea
82-
class="ant-input ant-input-borderless css-var-r1 ant-input-css-var ant-sender-input"
83-
style="overflow-y: hidden; resize: none;"
84-
/>
8585
<div
86-
class="ant-sender-actions-list"
86+
class="ant-sender-content"
8787
>
88+
<textarea
89+
class="ant-input ant-input-borderless css-var-r1 ant-input-css-var ant-sender-input"
90+
style="overflow-y: hidden; resize: none;"
91+
/>
8892
<div
89-
class="ant-sender-actions-list-presets ant-flex css-var-r1 ant-flex-rtl"
93+
class="ant-sender-actions-list"
9094
>
91-
<button
92-
class="ant-btn css-var-r1 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-btn-rtl ant-sender-actions-btn ant-sender-actions-btn-disabled"
93-
type="button"
95+
<div
96+
class="ant-sender-actions-list-presets ant-flex css-var-r1 ant-flex-rtl"
9497
>
95-
<span
96-
class="ant-btn-icon"
98+
<button
99+
class="ant-btn css-var-r1 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-btn-rtl ant-sender-actions-btn ant-sender-actions-btn-disabled"
100+
type="button"
97101
>
98102
<span
99-
aria-label="arrow-up"
100-
class="anticon anticon-arrow-up"
101-
role="img"
103+
class="ant-btn-icon"
102104
>
103-
<svg
104-
aria-hidden="true"
105-
data-icon="arrow-up"
106-
fill="currentColor"
107-
focusable="false"
108-
height="1em"
109-
viewBox="64 64 896 896"
110-
width="1em"
105+
<span
106+
aria-label="arrow-up"
107+
class="anticon anticon-arrow-up"
108+
role="img"
111109
>
112-
<path
113-
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
114-
/>
115-
</svg>
110+
<svg
111+
aria-hidden="true"
112+
data-icon="arrow-up"
113+
fill="currentColor"
114+
focusable="false"
115+
height="1em"
116+
viewBox="64 64 896 896"
117+
width="1em"
118+
>
119+
<path
120+
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
121+
/>
122+
</svg>
123+
</span>
116124
</span>
117-
</span>
118-
</button>
125+
</button>
126+
</div>
119127
</div>
120128
</div>
121129
</div>

‎components/sender/demo/_semantic.tsx

+54-10
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,71 @@
1+
import { SmileOutlined } from '@ant-design/icons';
2+
import { Sender } from '@ant-design/x';
3+
import { Button, Divider, Flex } from 'antd';
14
import React from 'react';
25
import SemanticPreview from '../../../.dumi/components/SemanticPreview';
36
import useLocale from '../../../.dumi/hooks/useLocale';
4-
import { Sender } from '@ant-design/x';
57

68
const locales = {
7-
cn: { input: '输入框', actions: '操作列表' },
9+
cn: {
10+
prefix: '前缀',
11+
input: '输入框',
12+
actions: '操作列表',
13+
},
814
en: {
15+
prefix: 'Prefix',
916
input: 'Input',
1017
actions: 'Action List',
1118
},
1219
};
1320

21+
const headerLocales = {
22+
cn: {
23+
header: '头部',
24+
content: '内容',
25+
},
26+
en: {
27+
header: 'Header',
28+
content: 'Content',
29+
},
30+
};
31+
1432
const App: React.FC = () => {
1533
const [locale] = useLocale(locales);
34+
const [headerLocale] = useLocale(headerLocales);
35+
1636
return (
17-
<SemanticPreview
18-
semantics={[
19-
{ name: 'input', desc: locale.input },
20-
{ name: 'actions', desc: locale.actions },
21-
]}
22-
>
23-
<Sender />
24-
</SemanticPreview>
37+
<Flex vertical>
38+
{/* Basic */}
39+
<SemanticPreview
40+
semantics={[
41+
{ name: 'prefix', desc: locale.prefix },
42+
{ name: 'input', desc: locale.input },
43+
{ name: 'actions', desc: locale.actions },
44+
]}
45+
>
46+
<Sender prefix={<Button type="text" icon={<SmileOutlined />} />} />
47+
</SemanticPreview>
48+
49+
<Divider style={{ margin: 0, padding: 0 }} />
50+
51+
{/* With Header */}
52+
<SemanticPreview
53+
semantics={[
54+
{ name: 'header', desc: headerLocale.header },
55+
{ name: 'content', desc: headerLocale.content },
56+
]}
57+
>
58+
{(injectProps) => (
59+
<Sender
60+
header={
61+
<Sender.Header open title="Header" {...injectProps}>
62+
Content
63+
</Sender.Header>
64+
}
65+
/>
66+
)}
67+
</SemanticPreview>
68+
</Flex>
2569
);
2670
};
2771

‎components/sender/demo/header.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## zh-CN
2+
3+
使用 `header` 自定义文件上传示例。
4+
5+
## en-US
6+
7+
Use `header` to customize the file upload example.

‎components/sender/demo/header.tsx

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { CloudUploadOutlined, LinkOutlined } from '@ant-design/icons';
2+
import { Sender } from '@ant-design/x';
3+
import { App, Button, Flex, Typography, theme } from 'antd';
4+
import React from 'react';
5+
6+
const Demo: React.FC = () => {
7+
const { message } = App.useApp();
8+
const { token } = theme.useToken();
9+
10+
const [open, setOpen] = React.useState(false);
11+
12+
const headerNode = (
13+
<Sender.Header title="Upload Sample" open={open} onOpenChange={setOpen}>
14+
<Flex vertical align="center" gap="small" style={{ marginBlock: token.paddingLG }}>
15+
<CloudUploadOutlined style={{ fontSize: '4em' }} />
16+
<Typography.Title level={5} style={{ margin: 0 }}>
17+
Drag file here (just demo)
18+
</Typography.Title>
19+
<Typography.Text type="secondary">
20+
Support pdf, doc, xlsx, ppt, txt, image file types
21+
</Typography.Text>
22+
<Button
23+
onClick={() => {
24+
message.info('Mock select file');
25+
}}
26+
>
27+
Select File
28+
</Button>
29+
</Flex>
30+
</Sender.Header>
31+
);
32+
33+
return (
34+
<Flex style={{ height: 350 }} align="end">
35+
<Sender
36+
header={headerNode}
37+
prefix={
38+
<Button
39+
type="text"
40+
icon={<LinkOutlined />}
41+
onClick={() => {
42+
setOpen(!open);
43+
}}
44+
/>
45+
}
46+
placeholder="← Click to open"
47+
onSubmit={() => {
48+
message.success('Send message successfully!');
49+
}}
50+
/>
51+
</Flex>
52+
);
53+
};
54+
55+
export default () => (
56+
<App>
57+
<Demo />
58+
</App>
59+
);

‎components/sender/index.en-US.md

+13
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*8yArQ43EGccAAA
2020
<code src="./demo/submitType.tsx">Submit type</code>
2121
<code src="./demo/speech.tsx">Speech input</code>
2222
<code src="./demo/actions.tsx">Custom actions</code>
23+
<code src="./demo/header.tsx">Header panel</code>
2324
<code src="./demo/send-style.tsx">Adjust style</code>
2425

2526
## API
@@ -37,6 +38,8 @@ Common props ref:[Common props](/docs/react/common-props)
3738
| defaultValue | Default value of input | string | - | - |
3839
| disabled | Whether to disable | boolean | false | - |
3940
| loading | Whether it is loading | boolean | false | - |
41+
| header | Header panel | ReactNode | - | - |
42+
| prefix | Prefix content | ReactNode | - | - |
4043
| rootClassName | Root element class name | string | - | - |
4144
| styles | Semantic DOM style | [See below](#semantic-dom) | - | - |
4245
| submitType | Submit type | SubmitType | `enter` \| `shiftEnter` | - |
@@ -45,6 +48,16 @@ Common props ref:[Common props](/docs/react/common-props)
4548
| onChange | Callback when input value changes | (value: string) => void | - | - |
4649
| onCancel | Callback when click cancel button | () => void | - | - |
4750

51+
### Sender.Header
52+
53+
| Property | Description | Type | Default | Version |
54+
| --- | --- | --- | --- | --- |
55+
| children | Panel content | ReactNode | - | - |
56+
| closable | Whether to close | boolean | true | - |
57+
| open | Whether to expand | boolean | - | - |
58+
| title | Title content | ReactNode | - | - |
59+
| onOpenChange | Callback when the expansion state changes | (open: boolean) => void | - | - |
60+
4861
## Semantic DOM
4962

5063
<code src="./demo/_semantic.tsx" simplify="true"></code>

‎components/sender/index.tsx

+76-39
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import getValue from 'rc-util/lib/utils/get';
77
import React from 'react';
88
import useXComponentConfig from '../_util/hooks/use-x-component-config';
99
import { useXProviderContext } from '../x-provider';
10+
import SenderHeader, { SendHeaderContext } from './SenderHeader';
1011
import { ActionButtonContext } from './components/ActionButton';
1112
import ClearButton from './components/ClearButton';
1213
import LoadingButton from './components/LoadingButton';
@@ -46,18 +47,22 @@ export interface SenderProps extends Pick<TextareaProps, 'placeholder' | 'onKeyP
4647
onKeyDown?: React.KeyboardEventHandler<any>;
4748
components?: SenderComponents;
4849
styles?: {
50+
prefix?: React.CSSProperties;
4951
input?: React.CSSProperties;
5052
actions?: React.CSSProperties;
5153
};
5254
rootClassName?: string;
5355
classNames?: {
56+
prefix?: string;
5457
input?: string;
5558
actions?: string;
5659
};
5760
style?: React.CSSProperties;
5861
className?: string;
5962
actions?: React.ReactNode | ActionsRender;
6063
allowSpeech?: boolean;
64+
prefix?: React.ReactNode;
65+
header?: React.ReactNode;
6166
}
6267

6368
function getComponent<T>(
@@ -68,7 +73,9 @@ function getComponent<T>(
6873
return getValue(components, path) || defaultComponent;
6974
}
7075

71-
const Sender: React.FC<SenderProps> = (props) => {
76+
const Sender: React.FC<SenderProps> & {
77+
Header: typeof SenderHeader;
78+
} = (props) => {
7279
const {
7380
prefixCls: customizePrefixCls,
7481
styles = {},
@@ -89,6 +96,8 @@ const Sender: React.FC<SenderProps> = (props) => {
8996
onKeyDown,
9097
disabled,
9198
allowSpeech,
99+
prefix,
100+
header,
92101
...rest
93102
} = props;
94103

@@ -243,46 +252,72 @@ const Sender: React.FC<SenderProps> = (props) => {
243252
style={{ ...contextConfig.style, ...style }}
244253
onMouseDown={onInternalMouseDown}
245254
>
246-
<InputTextArea
247-
{...inputProps}
248-
disabled={disabled}
249-
style={{ ...contextConfig.styles.input, ...styles.input }}
250-
className={classnames(inputCls, contextConfig.classNames.input, classNames.input)}
251-
autoSize={{ maxRows: 8 }}
252-
value={innerValue}
253-
onChange={(e) => {
254-
triggerValueChange((e.target as HTMLTextAreaElement).value);
255-
}}
256-
onPressEnter={onInternalKeyPress}
257-
onCompositionStart={onInternalCompositionStart}
258-
onCompositionEnd={onInternalCompositionEnd}
259-
onKeyDown={onKeyDown}
260-
readOnly={loading}
261-
variant="borderless"
262-
/>
263-
264-
{/* Action List */}
265-
<div
266-
className={classnames(actionListCls, contextConfig.classNames.actions, classNames.actions)}
267-
style={{ ...contextConfig.styles.actions, ...styles.actions }}
268-
>
269-
<ActionButtonContext.Provider
270-
value={{
271-
prefixCls: actionBtnCls,
272-
onSend: triggerSend,
273-
onSendDisabled: !innerValue,
274-
onClear: triggerClear,
275-
onClearDisabled: !innerValue,
276-
onCancel,
277-
onCancelDisabled: !loading,
278-
onSpeech: triggerSpeech,
279-
onSpeechDisabled: !speechPermission,
280-
speechRecording,
281-
disabled,
255+
{/* Header */}
256+
{header && (
257+
<SendHeaderContext.Provider value={{ prefixCls }}>{header}</SendHeaderContext.Provider>
258+
)}
259+
260+
<div className={`${prefixCls}-content`}>
261+
{/* Prefix */}
262+
{prefix && (
263+
<div
264+
className={classnames(
265+
`${prefixCls}-prefix`,
266+
contextConfig.classNames.prefix,
267+
classNames.prefix,
268+
)}
269+
style={{ ...contextConfig.styles.prefix, ...styles.prefix }}
270+
>
271+
{prefix}
272+
</div>
273+
)}
274+
275+
{/* Input */}
276+
<InputTextArea
277+
{...inputProps}
278+
disabled={disabled}
279+
style={{ ...contextConfig.styles.input, ...styles.input }}
280+
className={classnames(inputCls, contextConfig.classNames.input, classNames.input)}
281+
autoSize={{ maxRows: 8 }}
282+
value={innerValue}
283+
onChange={(e) => {
284+
triggerValueChange((e.target as HTMLTextAreaElement).value);
282285
}}
286+
onPressEnter={onInternalKeyPress}
287+
onCompositionStart={onInternalCompositionStart}
288+
onCompositionEnd={onInternalCompositionEnd}
289+
onKeyDown={onKeyDown}
290+
readOnly={loading}
291+
variant="borderless"
292+
/>
293+
294+
{/* Action List */}
295+
<div
296+
className={classnames(
297+
actionListCls,
298+
contextConfig.classNames.actions,
299+
classNames.actions,
300+
)}
301+
style={{ ...contextConfig.styles.actions, ...styles.actions }}
283302
>
284-
{actionNode}
285-
</ActionButtonContext.Provider>
303+
<ActionButtonContext.Provider
304+
value={{
305+
prefixCls: actionBtnCls,
306+
onSend: triggerSend,
307+
onSendDisabled: !innerValue,
308+
onClear: triggerClear,
309+
onClearDisabled: !innerValue,
310+
onCancel,
311+
onCancelDisabled: !loading,
312+
onSpeech: triggerSpeech,
313+
onSpeechDisabled: !speechPermission,
314+
speechRecording,
315+
disabled,
316+
}}
317+
>
318+
{actionNode}
319+
</ActionButtonContext.Provider>
320+
</div>
286321
</div>
287322
</div>,
288323
);
@@ -292,4 +327,6 @@ if (process.env.NODE_ENV !== 'production') {
292327
Sender.displayName = 'Sender';
293328
}
294329

330+
Sender.Header = SenderHeader;
331+
295332
export default Sender;

‎components/sender/index.zh-CN.md

+13
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*8yArQ43EGccAAA
2121
<code src="./demo/submitType.tsx">提交模式</code>
2222
<code src="./demo/speech.tsx">语音输入</code>
2323
<code src="./demo/actions.tsx">自定义按钮</code>
24+
<code src="./demo/header.tsx">展开面板</code>
2425
<code src="./demo/send-style.tsx">调整样式</code>
2526

2627
## API
@@ -38,6 +39,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*8yArQ43EGccAAA
3839
| defaultValue | 输入框默认值 | string | - | - |
3940
| disabled | 是否禁用 | boolean | false | - |
4041
| loading | 是否加载中 | boolean | false | - |
42+
| header | 头部面板 | ReactNode | - | - |
43+
| prefix | 前缀内容 | ReactNode | - | - |
4144
| rootClassName | 根元素样式类 | string | - | - |
4245
| styles | 语义化定义样式 | [见下](#semantic-dom) | - | - |
4346
| submitType | 提交模式 | SubmitType | `enter` \| `shiftEnter` | - |
@@ -46,6 +49,16 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*8yArQ43EGccAAA
4649
| onChange | 输入框值改变的回调 | (value: string) => void | - | - |
4750
| onCancel | 点击取消按钮的回调 | () => void | - | - |
4851

52+
### Sender.Header
53+
54+
| 属性 | 说明 | 类型 | 默认值 | 版本 |
55+
| ------------ | ------------------ | ----------------------- | ------ | ---- |
56+
| children | 面板内容 | ReactNode | - | - |
57+
| closable | 是否可关闭 | boolean | true | - |
58+
| open | 是否展开 | boolean | - | - |
59+
| title | 标题 | ReactNode | - | - |
60+
| onOpenChange | 展开状态改变的回调 | (open: boolean) => void | - | - |
61+
4962
## Semantic DOM
5063

5164
<code src="./demo/_semantic.tsx" simplify="true"></code>

‎components/sender/style/header.ts

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import type { SenderToken } from '.';
2+
import type { GenerateStyle } from '../../theme/cssinjs-utils';
3+
4+
const genSenderHeaderStyle: GenerateStyle<SenderToken> = (token) => {
5+
const { componentCls, calc } = token;
6+
7+
const headerCls = `${componentCls}-header`;
8+
9+
return {
10+
[componentCls]: {
11+
[headerCls]: {
12+
borderBottomWidth: token.lineWidth,
13+
borderBottomStyle: 'solid',
14+
borderBottomColor: token.colorBorder,
15+
16+
// ======================== Header ========================
17+
'&-header': {
18+
background: token.colorFillAlter,
19+
fontSize: token.fontSize,
20+
lineHeight: token.lineHeight,
21+
paddingBlock: calc(token.paddingSM).sub(token.lineWidthBold).equal(),
22+
paddingInlineStart: token.padding,
23+
paddingInlineEnd: token.paddingXS,
24+
display: 'flex',
25+
26+
[`${headerCls}-title`]: {
27+
flex: 'auto',
28+
},
29+
},
30+
31+
// ======================= Content ========================
32+
'&-content': {
33+
padding: token.padding,
34+
},
35+
36+
// ======================== Motion ========================
37+
'&-motion': {
38+
transition: ['height', 'border']
39+
.map((prop) => `${prop} ${token.motionDurationSlow}`)
40+
.join(','),
41+
overflow: 'hidden',
42+
43+
'&-enter-start, &-leave-active': {
44+
borderBottomColor: 'transparent',
45+
},
46+
47+
'&-hidden': {
48+
display: 'none',
49+
},
50+
},
51+
},
52+
},
53+
};
54+
};
55+
56+
export default genSenderHeaderStyle;

‎components/sender/style/index.ts

+24-11
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import { unit } from '@ant-design/cssinjs';
22
import { mergeToken } from '@ant-design/cssinjs-utils';
33
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/cssinjs-utils';
44
import { genStyleHooks } from '../../theme/genStyleUtils';
5+
import genSenderHeaderStyle from './header';
56

67
// biome-ignore lint/suspicious/noEmptyInterface: ComponentToken need to be empty by default
78
export interface ComponentToken {}
89

9-
interface SenderToken extends FullToken<'Sender'> {
10+
export interface SenderToken extends FullToken<'Sender'> {
1011
SenderContentMaxWidth: number | string;
1112
}
1213

@@ -16,15 +17,9 @@ const genSenderStyle: GenerateStyle<SenderToken> = (token) => {
1617
return {
1718
[componentCls]: {
1819
position: 'relative',
19-
display: 'flex',
20-
gap: paddingXS,
2120
width: '100%',
2221

23-
paddingBlock: paddingSM,
24-
paddingInlineStart: padding,
25-
paddingInlineEnd: paddingSM,
2622
boxSizing: 'border-box',
27-
alignItems: 'flex-end',
2823
boxShadow: `${token.boxShadowTertiary}`,
2924
transition: `background ${token.motionDurationSlow}`,
3025

@@ -73,8 +68,26 @@ const genSenderStyle: GenerateStyle<SenderToken> = (token) => {
7368
direction: 'rtl',
7469
},
7570

71+
// ============================ Content ============================
72+
[`${componentCls}-content`]: {
73+
display: 'flex',
74+
gap: paddingXS,
75+
width: '100%',
76+
77+
paddingBlock: paddingSM,
78+
paddingInlineStart: padding,
79+
paddingInlineEnd: paddingSM,
80+
boxSizing: 'border-box',
81+
alignItems: 'flex-end',
82+
},
83+
84+
// ============================ Prefix =============================
85+
[`${componentCls}-prefix`]: {
86+
flex: 'none',
87+
},
88+
7689
// ============================= Input =============================
77-
[`& ${componentCls}-input`]: {
90+
[`${componentCls}-input`]: {
7891
padding: 0,
7992
borderRadius: 0,
8093
flex: 'auto',
@@ -83,7 +96,7 @@ const genSenderStyle: GenerateStyle<SenderToken> = (token) => {
8396
},
8497

8598
// ============================ Actions ============================
86-
[`& ${componentCls}-actions-list`]: {
99+
[`${componentCls}-actions-list`]: {
87100
flex: 'none',
88101
display: 'flex',
89102

@@ -92,7 +105,7 @@ const genSenderStyle: GenerateStyle<SenderToken> = (token) => {
92105
},
93106
},
94107

95-
[`& ${componentCls}-actions-btn`]: {
108+
[`${componentCls}-actions-btn`]: {
96109
'&-disabled': {
97110
opacity: 0.45,
98111
},
@@ -126,7 +139,7 @@ export default genStyleHooks<'Sender'>(
126139
const SenderToken = mergeToken<SenderToken>(token, {
127140
SenderContentMaxWidth: `calc(100% - ${unit(calc(paddingXS).add(32).equal())})`,
128141
});
129-
return genSenderStyle(SenderToken);
142+
return [genSenderStyle(SenderToken), genSenderHeaderStyle(SenderToken)];
130143
},
131144
prepareComponentToken,
132145
);

‎components/suggestion/__tests__/__snapshots__/demo-extend.test.ts.snap

+66-58
Original file line numberDiff line numberDiff line change
@@ -8,45 +8,49 @@ Array [
88
<div
99
class="ant-sender css-var-rb"
1010
>
11-
<textarea
12-
class="ant-input ant-input-borderless css-var-rb ant-input-css-var ant-sender-input"
13-
placeholder="输入 / 获取建议"
14-
style="overflow-y: hidden; resize: none;"
15-
/>
1611
<div
17-
class="ant-sender-actions-list"
12+
class="ant-sender-content"
1813
>
14+
<textarea
15+
class="ant-input ant-input-borderless css-var-rb ant-input-css-var ant-sender-input"
16+
placeholder="输入 / 获取建议"
17+
style="overflow-y: hidden; resize: none;"
18+
/>
1919
<div
20-
class="ant-sender-actions-list-presets ant-flex css-var-rb"
20+
class="ant-sender-actions-list"
2121
>
22-
<button
23-
class="ant-btn css-var-rb ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
24-
type="button"
22+
<div
23+
class="ant-sender-actions-list-presets ant-flex css-var-rb"
2524
>
26-
<span
27-
class="ant-btn-icon"
25+
<button
26+
class="ant-btn css-var-rb ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
27+
type="button"
2828
>
2929
<span
30-
aria-label="arrow-up"
31-
class="anticon anticon-arrow-up"
32-
role="img"
30+
class="ant-btn-icon"
3331
>
34-
<svg
35-
aria-hidden="true"
36-
data-icon="arrow-up"
37-
fill="currentColor"
38-
focusable="false"
39-
height="1em"
40-
viewBox="64 64 896 896"
41-
width="1em"
32+
<span
33+
aria-label="arrow-up"
34+
class="anticon anticon-arrow-up"
35+
role="img"
4236
>
43-
<path
44-
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
45-
/>
46-
</svg>
37+
<svg
38+
aria-hidden="true"
39+
data-icon="arrow-up"
40+
fill="currentColor"
41+
focusable="false"
42+
height="1em"
43+
viewBox="64 64 896 896"
44+
width="1em"
45+
>
46+
<path
47+
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
48+
/>
49+
</svg>
50+
</span>
4751
</span>
48-
</span>
49-
</button>
52+
</button>
53+
</div>
5054
</div>
5155
</div>
5256
</div>
@@ -178,45 +182,49 @@ Array [
178182
<div
179183
class="ant-sender css-var-r7"
180184
>
181-
<textarea
182-
class="ant-input ant-input-borderless css-var-r7 ant-input-css-var ant-sender-input"
183-
placeholder="输入 / 获取建议"
184-
style="overflow-y: hidden; resize: none;"
185-
/>
186185
<div
187-
class="ant-sender-actions-list"
186+
class="ant-sender-content"
188187
>
188+
<textarea
189+
class="ant-input ant-input-borderless css-var-r7 ant-input-css-var ant-sender-input"
190+
placeholder="输入 / 获取建议"
191+
style="overflow-y: hidden; resize: none;"
192+
/>
189193
<div
190-
class="ant-sender-actions-list-presets ant-flex css-var-r7"
194+
class="ant-sender-actions-list"
191195
>
192-
<button
193-
class="ant-btn css-var-r7 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
194-
type="button"
196+
<div
197+
class="ant-sender-actions-list-presets ant-flex css-var-r7"
195198
>
196-
<span
197-
class="ant-btn-icon"
199+
<button
200+
class="ant-btn css-var-r7 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
201+
type="button"
198202
>
199203
<span
200-
aria-label="arrow-up"
201-
class="anticon anticon-arrow-up"
202-
role="img"
204+
class="ant-btn-icon"
203205
>
204-
<svg
205-
aria-hidden="true"
206-
data-icon="arrow-up"
207-
fill="currentColor"
208-
focusable="false"
209-
height="1em"
210-
viewBox="64 64 896 896"
211-
width="1em"
206+
<span
207+
aria-label="arrow-up"
208+
class="anticon anticon-arrow-up"
209+
role="img"
212210
>
213-
<path
214-
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
215-
/>
216-
</svg>
211+
<svg
212+
aria-hidden="true"
213+
data-icon="arrow-up"
214+
fill="currentColor"
215+
focusable="false"
216+
height="1em"
217+
viewBox="64 64 896 896"
218+
width="1em"
219+
>
220+
<path
221+
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
222+
/>
223+
</svg>
224+
</span>
217225
</span>
218-
</span>
219-
</button>
226+
</button>
227+
</div>
220228
</div>
221229
</div>
222230
</div>

‎components/suggestion/__tests__/__snapshots__/demo.test.ts.snap

+64-56
Original file line numberDiff line numberDiff line change
@@ -7,44 +7,48 @@ exports[`renders components/suggestion/demo/basic.tsx correctly 1`] = `
77
<div
88
class="ant-sender css-var-R0"
99
>
10-
<textarea
11-
class="ant-input ant-input-borderless css-var-R0 ant-input-css-var ant-sender-input"
12-
placeholder="输入 / 获取建议"
13-
/>
1410
<div
15-
class="ant-sender-actions-list"
11+
class="ant-sender-content"
1612
>
13+
<textarea
14+
class="ant-input ant-input-borderless css-var-R0 ant-input-css-var ant-sender-input"
15+
placeholder="输入 / 获取建议"
16+
/>
1717
<div
18-
class="ant-sender-actions-list-presets ant-flex css-var-R0"
18+
class="ant-sender-actions-list"
1919
>
20-
<button
21-
class="ant-btn css-var-R0 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
22-
type="button"
20+
<div
21+
class="ant-sender-actions-list-presets ant-flex css-var-R0"
2322
>
24-
<span
25-
class="ant-btn-icon"
23+
<button
24+
class="ant-btn css-var-R0 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
25+
type="button"
2626
>
2727
<span
28-
aria-label="arrow-up"
29-
class="anticon anticon-arrow-up"
30-
role="img"
28+
class="ant-btn-icon"
3129
>
32-
<svg
33-
aria-hidden="true"
34-
data-icon="arrow-up"
35-
fill="currentColor"
36-
focusable="false"
37-
height="1em"
38-
viewBox="64 64 896 896"
39-
width="1em"
30+
<span
31+
aria-label="arrow-up"
32+
class="anticon anticon-arrow-up"
33+
role="img"
4034
>
41-
<path
42-
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
43-
/>
44-
</svg>
35+
<svg
36+
aria-hidden="true"
37+
data-icon="arrow-up"
38+
fill="currentColor"
39+
focusable="false"
40+
height="1em"
41+
viewBox="64 64 896 896"
42+
width="1em"
43+
>
44+
<path
45+
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
46+
/>
47+
</svg>
48+
</span>
4549
</span>
46-
</span>
47-
</button>
50+
</button>
51+
</div>
4852
</div>
4953
</div>
5054
</div>
@@ -58,44 +62,48 @@ exports[`renders components/suggestion/demo/block.tsx correctly 1`] = `
5862
<div
5963
class="ant-sender css-var-R0"
6064
>
61-
<textarea
62-
class="ant-input ant-input-borderless css-var-R0 ant-input-css-var ant-sender-input"
63-
placeholder="输入 / 获取建议"
64-
/>
6565
<div
66-
class="ant-sender-actions-list"
66+
class="ant-sender-content"
6767
>
68+
<textarea
69+
class="ant-input ant-input-borderless css-var-R0 ant-input-css-var ant-sender-input"
70+
placeholder="输入 / 获取建议"
71+
/>
6872
<div
69-
class="ant-sender-actions-list-presets ant-flex css-var-R0"
73+
class="ant-sender-actions-list"
7074
>
71-
<button
72-
class="ant-btn css-var-R0 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
73-
type="button"
75+
<div
76+
class="ant-sender-actions-list-presets ant-flex css-var-R0"
7477
>
75-
<span
76-
class="ant-btn-icon"
78+
<button
79+
class="ant-btn css-var-R0 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
80+
type="button"
7781
>
7882
<span
79-
aria-label="arrow-up"
80-
class="anticon anticon-arrow-up"
81-
role="img"
83+
class="ant-btn-icon"
8284
>
83-
<svg
84-
aria-hidden="true"
85-
data-icon="arrow-up"
86-
fill="currentColor"
87-
focusable="false"
88-
height="1em"
89-
viewBox="64 64 896 896"
90-
width="1em"
85+
<span
86+
aria-label="arrow-up"
87+
class="anticon anticon-arrow-up"
88+
role="img"
9189
>
92-
<path
93-
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
94-
/>
95-
</svg>
90+
<svg
91+
aria-hidden="true"
92+
data-icon="arrow-up"
93+
fill="currentColor"
94+
focusable="false"
95+
height="1em"
96+
viewBox="64 64 896 896"
97+
width="1em"
98+
>
99+
<path
100+
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
101+
/>
102+
</svg>
103+
</span>
96104
</span>
97-
</span>
98-
</button>
105+
</button>
106+
</div>
99107
</div>
100108
</div>
101109
</div>

‎components/useXChat/__tests__/__snapshots__/demo.test.ts.snap

+93-81
Original file line numberDiff line numberDiff line change
@@ -11,43 +11,47 @@ exports[`renders components/useXChat/demo/basic.tsx correctly 1`] = `
1111
<div
1212
class="ant-sender css-var-R0"
1313
>
14-
<textarea
15-
class="ant-input ant-input-borderless css-var-R0 ant-input-css-var ant-sender-input"
16-
/>
1714
<div
18-
class="ant-sender-actions-list"
15+
class="ant-sender-content"
1916
>
17+
<textarea
18+
class="ant-input ant-input-borderless css-var-R0 ant-input-css-var ant-sender-input"
19+
/>
2020
<div
21-
class="ant-sender-actions-list-presets ant-flex css-var-R0"
21+
class="ant-sender-actions-list"
2222
>
23-
<button
24-
class="ant-btn css-var-R0 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
25-
type="button"
23+
<div
24+
class="ant-sender-actions-list-presets ant-flex css-var-R0"
2625
>
27-
<span
28-
class="ant-btn-icon"
26+
<button
27+
class="ant-btn css-var-R0 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
28+
type="button"
2929
>
3030
<span
31-
aria-label="arrow-up"
32-
class="anticon anticon-arrow-up"
33-
role="img"
31+
class="ant-btn-icon"
3432
>
35-
<svg
36-
aria-hidden="true"
37-
data-icon="arrow-up"
38-
fill="currentColor"
39-
focusable="false"
40-
height="1em"
41-
viewBox="64 64 896 896"
42-
width="1em"
33+
<span
34+
aria-label="arrow-up"
35+
class="anticon anticon-arrow-up"
36+
role="img"
4337
>
44-
<path
45-
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
46-
/>
47-
</svg>
38+
<svg
39+
aria-hidden="true"
40+
data-icon="arrow-up"
41+
fill="currentColor"
42+
focusable="false"
43+
height="1em"
44+
viewBox="64 64 896 896"
45+
width="1em"
46+
>
47+
<path
48+
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
49+
/>
50+
</svg>
51+
</span>
4852
</span>
49-
</span>
50-
</button>
53+
</button>
54+
</div>
5155
</div>
5256
</div>
5357
</div>
@@ -65,43 +69,47 @@ exports[`renders components/useXChat/demo/stream.tsx correctly 1`] = `
6569
<div
6670
class="ant-sender css-var-R0"
6771
>
68-
<textarea
69-
class="ant-input ant-input-borderless css-var-R0 ant-input-css-var ant-sender-input"
70-
/>
7172
<div
72-
class="ant-sender-actions-list"
73+
class="ant-sender-content"
7374
>
75+
<textarea
76+
class="ant-input ant-input-borderless css-var-R0 ant-input-css-var ant-sender-input"
77+
/>
7478
<div
75-
class="ant-sender-actions-list-presets ant-flex css-var-R0"
79+
class="ant-sender-actions-list"
7680
>
77-
<button
78-
class="ant-btn css-var-R0 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
79-
type="button"
81+
<div
82+
class="ant-sender-actions-list-presets ant-flex css-var-R0"
8083
>
81-
<span
82-
class="ant-btn-icon"
84+
<button
85+
class="ant-btn css-var-R0 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
86+
type="button"
8387
>
8488
<span
85-
aria-label="arrow-up"
86-
class="anticon anticon-arrow-up"
87-
role="img"
89+
class="ant-btn-icon"
8890
>
89-
<svg
90-
aria-hidden="true"
91-
data-icon="arrow-up"
92-
fill="currentColor"
93-
focusable="false"
94-
height="1em"
95-
viewBox="64 64 896 896"
96-
width="1em"
91+
<span
92+
aria-label="arrow-up"
93+
class="anticon anticon-arrow-up"
94+
role="img"
9795
>
98-
<path
99-
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
100-
/>
101-
</svg>
96+
<svg
97+
aria-hidden="true"
98+
data-icon="arrow-up"
99+
fill="currentColor"
100+
focusable="false"
101+
height="1em"
102+
viewBox="64 64 896 896"
103+
width="1em"
104+
>
105+
<path
106+
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
107+
/>
108+
</svg>
109+
</span>
102110
</span>
103-
</span>
104-
</button>
111+
</button>
112+
</div>
105113
</div>
106114
</div>
107115
</div>
@@ -130,43 +138,47 @@ exports[`renders components/useXChat/demo/suggestions.tsx correctly 1`] = `
130138
<div
131139
class="ant-sender css-var-R0"
132140
>
133-
<textarea
134-
class="ant-input ant-input-borderless css-var-R0 ant-input-css-var ant-sender-input"
135-
/>
136141
<div
137-
class="ant-sender-actions-list"
142+
class="ant-sender-content"
138143
>
144+
<textarea
145+
class="ant-input ant-input-borderless css-var-R0 ant-input-css-var ant-sender-input"
146+
/>
139147
<div
140-
class="ant-sender-actions-list-presets ant-flex css-var-R0"
148+
class="ant-sender-actions-list"
141149
>
142-
<button
143-
class="ant-btn css-var-R0 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
144-
type="button"
150+
<div
151+
class="ant-sender-actions-list-presets ant-flex css-var-R0"
145152
>
146-
<span
147-
class="ant-btn-icon"
153+
<button
154+
class="ant-btn css-var-R0 ant-btn-circle ant-btn-primary ant-btn-color-primary ant-btn-variant-solid ant-btn-icon-only ant-sender-actions-btn ant-sender-actions-btn-disabled"
155+
type="button"
148156
>
149157
<span
150-
aria-label="arrow-up"
151-
class="anticon anticon-arrow-up"
152-
role="img"
158+
class="ant-btn-icon"
153159
>
154-
<svg
155-
aria-hidden="true"
156-
data-icon="arrow-up"
157-
fill="currentColor"
158-
focusable="false"
159-
height="1em"
160-
viewBox="64 64 896 896"
161-
width="1em"
160+
<span
161+
aria-label="arrow-up"
162+
class="anticon anticon-arrow-up"
163+
role="img"
162164
>
163-
<path
164-
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
165-
/>
166-
</svg>
165+
<svg
166+
aria-hidden="true"
167+
data-icon="arrow-up"
168+
fill="currentColor"
169+
focusable="false"
170+
height="1em"
171+
viewBox="64 64 896 896"
172+
width="1em"
173+
>
174+
<path
175+
d="M868 545.5L536.1 163a31.96 31.96 0 00-48.3 0L156 545.5a7.97 7.97 0 006 13.2h81c4.6 0 9-2 12.1-5.5L474 300.9V864c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V300.9l218.9 252.3c3 3.5 7.4 5.5 12.1 5.5h81c6.8 0 10.5-8 6-13.2z"
176+
/>
177+
</svg>
178+
</span>
167179
</span>
168-
</span>
169-
</button>
180+
</button>
181+
</div>
170182
</div>
171183
</div>
172184
</div>

‎mako.config.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@
55
},
66
"codeSplitting": {
77
"strategy": "auto"
8-
},
9-
"moduleIdStrategy": "hashed"
8+
}
109
}

0 commit comments

Comments
 (0)
Please sign in to comment.