listpage-next 0.0.182 → 0.0.187

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,453 +0,0 @@
1
- # Next Page Creator
2
-
3
- 基于 Ant Design 的 React 组件库,专注于提供高质量的筛选表单组件。
4
-
5
- ## 安装
6
-
7
- ```bash
8
- npm install listpage-next
9
- # 或
10
- pnpm install listpage-next
11
- # 或
12
- yarn add listpage-next
13
- ```
14
-
15
- ## 快速开始
16
-
17
- ```tsx
18
- import { FilterForm } from 'listpage-next';
19
- import { DatePicker, Select } from 'antd';
20
-
21
- const App = () => {
22
- const options = [
23
- {
24
- name: 'title',
25
- label: '标题',
26
- component: 'input',
27
- },
28
- {
29
- name: 'type',
30
- label: '类型',
31
- component: <Select />,
32
- },
33
- ];
34
-
35
- const handleSubmit = (values) => {
36
- console.log('表单数据:', values);
37
- };
38
-
39
- return <FilterForm options={options} onSubmit={handleSubmit} />;
40
- };
41
- ```
42
-
43
- ## 组件列表
44
-
45
- ### FilterForm
46
-
47
- FilterForm 是一个基于 Ant Design Form 的筛选表单组件,支持灵活的表单项配置和网格布局。
48
-
49
- #### 组件属性说明
50
-
51
- ##### FilterFormProps
52
-
53
- | 属性名 | 类型 | 默认值 | 必填 | 描述 |
54
- |--------|------|--------|------|------|
55
- | options | `FilterFormOption[]` | - | ✅ | 表单项配置数组,定义表单的结构和行为 |
56
- | initialValues | `FormValue` | `{}` | ❌ | 表单初始值,支持泛型类型约束 |
57
- | onSubmit | `(values?: FormValue) => void` | - | ❌ | 表单提交回调函数,参数为当前表单值 |
58
- | onReset | `() => void` | - | ❌ | 表单重置回调函数 |
59
-
60
- ##### FilterFormOption
61
-
62
- | 属性名 | 类型 | 默认值 | 必填 | 描述 |
63
- |--------|------|--------|------|------|
64
- | name | `string` | - | ✅ | 表单项字段名,用于数据收集和验证 |
65
- | label | `ReactNode` | - | ❌ | 表单项标签,支持文本或 React 元素 |
66
- | component | `ComponentType`| ReactElement` | `'input'` | ❌ | 表单控件,支持字符串类型或 React 组件 |
67
- | colSpan | `number` | `2` | ❌ | 网格列跨度(1-12),控制表单项宽度 |
68
- | formItemProps | `Omit<FormItemProps, 'children'>` | - | ❌ | Ant Design Form.Item 的属性配置 |
69
-
70
- ##### ComponentType
71
-
72
- 支持的字符串类型组件:
73
-
74
- - `'input'`: 输入框组件(默认)
75
- - `'select'`: 选择器组件
76
-
77
- #### 使用示例
78
-
79
- ##### 基础用法
80
-
81
- ```tsx
82
- import React from 'react';
83
- import { FilterForm } from 'listpage-next';
84
-
85
- const BasicExample = () => {
86
- const options = [
87
- {
88
- name: 'username',
89
- label: '用户名',
90
- component: 'input',
91
- },
92
- {
93
- name: 'status',
94
- label: '状态',
95
- component: 'select',
96
- },
97
- ];
98
-
99
- const handleSubmit = (values) => {
100
- console.log('提交数据:', values);
101
- // 输出: { username: '输入的用户名', status: '选择的状态' }
102
- };
103
-
104
- const handleReset = () => {
105
- console.log('表单已重置');
106
- };
107
-
108
- return (
109
- <FilterForm
110
- options={options}
111
- onSubmit={handleSubmit}
112
- onReset={handleReset}
113
- />
114
- );
115
- };
116
- ```
117
-
118
- ##### 使用 Ant Design 组件
119
-
120
- ```tsx
121
- import React from 'react';
122
- import { FilterForm } from 'listpage-next';
123
- import { DatePicker, Select, Input } from 'antd';
124
-
125
- const { RangePicker } = DatePicker;
126
- const { Option } = Select;
127
-
128
- const AdvancedExample = () => {
129
- const options = [
130
- {
131
- name: 'keyword',
132
- label: '关键词',
133
- component: <Input placeholder="请输入关键词" />,
134
- colSpan: 3, // 占用3列宽度
135
- },
136
- {
137
- name: 'category',
138
- label: '分类',
139
- component: (
140
- <Select placeholder="请选择分类" allowClear>
141
- <Option value="tech">技术</Option>
142
- <Option value="business">商业</Option>
143
- <Option value="design">设计</Option>
144
- </Select>
145
- ),
146
- colSpan: 2,
147
- },
148
- {
149
- name: 'dateRange',
150
- label: '时间范围',
151
- component: <RangePicker />,
152
- colSpan: 4, // 日期范围选择器通常需要更多空间
153
- },
154
- {
155
- name: 'priority',
156
- label: '优先级',
157
- component: (
158
- <Select placeholder="选择优先级">
159
- <Option value="high">高</Option>
160
- <Option value="medium">中</Option>
161
- <Option value="low">低</Option>
162
- </Select>
163
- ),
164
- colSpan: 2,
165
- },
166
- ];
167
-
168
- const handleSubmit = (values) => {
169
- console.log('筛选条件:', values);
170
- // 处理表单数据,如发送 API 请求
171
- };
172
-
173
- return <FilterForm options={options} onSubmit={handleSubmit} />;
174
- };
175
- ```
176
-
177
- ##### 带初始值和表单验证
178
-
179
- ```tsx
180
- import React from 'react';
181
- import { FilterForm } from 'listpage-next';
182
- import { Input, Select } from 'antd';
183
-
184
- interface FormData {
185
- title: string;
186
- type: 'article' | 'video' | 'image';
187
- tags: string[];
188
- }
189
-
190
- const ValidationExample = () => {
191
- const initialValues: FormData = {
192
- title: '默认标题',
193
- type: 'article',
194
- tags: ['react'],
195
- };
196
-
197
- const options = [
198
- {
199
- name: 'title',
200
- label: '标题',
201
- component: <Input placeholder="请输入标题" />,
202
- formItemProps: {
203
- rules: [
204
- { required: true, message: '请输入标题' },
205
- { min: 2, message: '标题至少2个字符' },
206
- ],
207
- },
208
- colSpan: 4,
209
- },
210
- {
211
- name: 'type',
212
- label: '内容类型',
213
- component: (
214
- <Select>
215
- <Select.Option value="article">文章</Select.Option>
216
- <Select.Option value="video">视频</Select.Option>
217
- <Select.Option value="image">图片</Select.Option>
218
- </Select>
219
- ),
220
- formItemProps: {
221
- rules: [{ required: true, message: '请选择内容类型' }],
222
- },
223
- colSpan: 2,
224
- },
225
- {
226
- name: 'tags',
227
- label: '标签',
228
- component: (
229
- <Select mode="multiple" placeholder="选择标签">
230
- <Select.Option value="react">React</Select.Option>
231
- <Select.Option value="vue">Vue</Select.Option>
232
- <Select.Option value="angular">Angular</Select.Option>
233
- </Select>
234
- ),
235
- colSpan: 3,
236
- },
237
- ];
238
-
239
- const handleSubmit = (values: FormData) => {
240
- console.log('验证通过,提交数据:', values);
241
- };
242
-
243
- return (
244
- <FilterForm<FormData>
245
- options={options}
246
- initialValues={initialValues}
247
- onSubmit={handleSubmit}
248
- />
249
- );
250
- };
251
- ```
252
-
253
- ##### 响应式布局示例
254
-
255
- ```tsx
256
- import React from 'react';
257
- import { FilterForm } from 'listpage-next';
258
- import { Input, Select, DatePicker } from 'antd';
259
-
260
- const ResponsiveExample = () => {
261
- const options = [
262
- {
263
- name: 'search',
264
- label: '搜索',
265
- component: <Input.Search placeholder="输入搜索关键词" />,
266
- colSpan: 6, // 在12列网格中占一半宽度
267
- },
268
- {
269
- name: 'status',
270
- label: '状态',
271
- component: (
272
- <Select placeholder="选择状态">
273
- <Select.Option value="active">激活</Select.Option>
274
- <Select.Option value="inactive">未激活</Select.Option>
275
- </Select>
276
- ),
277
- colSpan: 3, // 占1/4宽度
278
- },
279
- {
280
- name: 'date',
281
- label: '创建日期',
282
- component: <DatePicker />,
283
- colSpan: 3, // 占1/4宽度
284
- },
285
- {
286
- name: 'region',
287
- label: '地区',
288
- component: (
289
- <Select placeholder="选择地区" allowClear>
290
- <Select.Option value="north">北方</Select.Option>
291
- <Select.Option value="south">南方</Select.Option>
292
- </Select>
293
- ),
294
- colSpan: 4, // 占1/3宽度
295
- },
296
- {
297
- name: 'department',
298
- label: '部门',
299
- component: <Select placeholder="选择部门" />,
300
- colSpan: 4, // 占1/3宽度
301
- },
302
- {
303
- name: 'level',
304
- label: '级别',
305
- component: <Select placeholder="选择级别" />,
306
- colSpan: 4, // 占1/3宽度
307
- },
308
- ];
309
-
310
- return <FilterForm options={options} onSubmit={console.log} />;
311
- };
312
- ```
313
-
314
- #### 注意事项
315
-
316
- ##### 特殊行为和限制
317
-
318
- 1. **网格布局系统**: FilterForm 使用 12 列网格系统,`colSpan` 属性值应在 1-12 之间
319
- 2. **表单验证**: 组件内部使用 Ant Design Form,支持完整的表单验证功能
320
- 3. **组件类型**: `component` 属性支持字符串类型('input'、'select')和 React 元素
321
- 4. **数据收集**: 表单数据通过 `name` 属性收集,确保每个表单项的 `name` 唯一
322
-
323
- ##### 最佳实践建议
324
-
325
- 1. **合理使用 colSpan**:
326
- - 短文本输入框建议使用 `colSpan: 2-3`
327
- - 日期范围选择器建议使用 `colSpan: 4-6`
328
- - 搜索框可以使用更大的 `colSpan: 6-8`
329
-
330
- 2. **组件选择策略**:
331
- ```tsx
332
- // ✅ 推荐:使用具体的 Ant Design 组件
333
- {
334
- name: 'category',
335
- component: <Select placeholder="请选择分类" allowClear />
336
- }
337
-
338
- // ✅ 可接受:使用字符串类型(适用于简单场景)
339
- {
340
- name: 'keyword',
341
- component: 'input'
342
- }
343
- ```
344
-
345
- 3. **TypeScript 类型约束**:
346
- ```tsx
347
- // ✅ 推荐:使用泛型约束表单数据类型
348
- interface SearchForm {
349
- keyword: string;
350
- status: 'active' | 'inactive';
351
- }
352
-
353
- <FilterForm<SearchForm>
354
- options={options}
355
- onSubmit={(values: SearchForm) => {
356
- // values 具有完整的类型提示
357
- }}
358
- />
359
- ```
360
-
361
- 4. **表单验证配置**:
362
- ```tsx
363
- // ✅ 推荐:在 formItemProps 中配置验证规则
364
- {
365
- name: 'email',
366
- label: '邮箱',
367
- component: <Input type="email" />,
368
- formItemProps: {
369
- rules: [
370
- { required: true, message: '请输入邮箱' },
371
- { type: 'email', message: '请输入有效的邮箱地址' }
372
- ]
373
- }
374
- }
375
- ```
376
-
377
- ##### 常见问题及解决方案
378
-
379
- 1. **Q: 表单项不显示或布局异常**
380
- ```tsx
381
- // ❌ 问题:colSpan 超出范围
382
- { name: 'field', colSpan: 15 } // 超出12列限制
383
-
384
- // ✅ 解决:使用合理的 colSpan 值
385
- { name: 'field', colSpan: 6 } // 占一半宽度
386
- ```
387
-
388
- 2. **Q: 自定义组件数据不更新**
389
- ```tsx
390
- // ❌ 问题:自定义组件未正确处理 value 和 onChange
391
- const CustomComponent = () => <input />; // 缺少受控属性
392
-
393
- // ✅ 解决:确保组件支持受控模式
394
- const CustomComponent = ({ value, onChange }) => (
395
- <input value={value} onChange={(e) => onChange(e.target.value)} />
396
- );
397
- ```
398
-
399
- 3. **Q: 表单重置后初始值丢失**
400
- ```tsx
401
- // ✅ 解决:确保 initialValues 正确设置
402
- <FilterForm
403
- initialValues={{ status: 'active' }} // 重置时会恢复到此值
404
- options={options}
405
- />
406
- ```
407
-
408
- 4. **Q: 表单验证不生效**
409
- ```tsx
410
- // ❌ 问题:验证规则配置位置错误
411
- {
412
- name: 'field',
413
- rules: [{ required: true }] // 错误位置
414
- }
415
-
416
- // ✅ 解决:在 formItemProps 中配置
417
- {
418
- name: 'field',
419
- formItemProps: {
420
- rules: [{ required: true, message: '此字段为必填项' }]
421
- }
422
- }
423
- ```
424
-
425
- ## 技术栈
426
-
427
- - **React**: ^19.1.1
428
- - **Ant Design**: ^5.27.3
429
- - **TypeScript**: ^5.9.2
430
- - **Styled Components**: ^6.1.19
431
- - **Lodash**: ^4.17.21
432
- - **ahooks**: ^3.9.5
433
- - **dayjs**: ^1.11.18
434
-
435
- ## 开发
436
-
437
- ```bash
438
- # 安装依赖
439
- pnpm install
440
-
441
- # 启动开发服务器
442
- pnpm dev
443
-
444
- # 构建
445
- pnpm build
446
-
447
- # 格式化代码
448
- pnpm format
449
- ```
450
-
451
- ## 许可证
452
-
453
- MIT
@@ -1,15 +1,10 @@
1
1
  import styled_components from "styled-components";
2
2
  const PageLoading = styled_components.div`
3
3
  align-items: center;
4
- bottom: 0;
5
4
  display: flex;
6
5
  height: 100%;
7
- justify-content: center;
8
- left: 0;
9
- position: fixed;
10
- right: 0;
11
- top: 0;
12
6
  width: 100%;
7
+ justify-content: center;
13
8
  overflow: hidden;
14
9
 
15
10
  &::after {
@@ -3,9 +3,9 @@ import { BaseMessageInfo, ChatActionEvent, ChatRender, ChatRequest } from '../..
3
3
  export interface ChatPageProps<SessionData = any, MessageInfo extends BaseMessageInfo = any> {
4
4
  logo?: string;
5
5
  title?: string;
6
+ action: ChatActionEvent<SessionData>;
6
7
  children?: ReactNode;
7
8
  request: ChatRequest<SessionData, MessageInfo>;
8
9
  render: ChatRender<MessageInfo>;
9
- action: ChatActionEvent<SessionData>;
10
10
  }
11
11
  export declare const ChatPage: (props: ChatPageProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,5 @@
1
+ import { ReactNode } from 'react';
1
2
  export interface SiderProps {
2
- children?: React.ReactNode;
3
+ children?: ReactNode;
3
4
  }
4
5
  export declare const Sider: (props: SiderProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,14 +1,14 @@
1
- import { RefObject } from 'react';
1
+ import { RefObject, CSSProperties } from 'react';
2
2
  import { BaseMessageInfo, ChatRender, ChatRequest } from '../../context';
3
3
  import { ChatInstance } from '../../context/useChatContext';
4
4
  import { ChatSenderProps } from '../ChatSender';
5
5
  export interface SimplifyChatPageProps<SessionData = any, MessageInfo extends BaseMessageInfo = any> {
6
6
  senderProps?: ChatSenderProps;
7
- request: ChatRequest<SessionData, MessageInfo>;
8
- render: ChatRender<MessageInfo>;
9
- style?: React.CSSProperties;
7
+ style?: CSSProperties;
10
8
  initialMessages?: MessageInfo[];
11
9
  chatRef?: RefObject<ChatInstance>;
10
+ request: ChatRequest<SessionData, MessageInfo>;
11
+ render: ChatRender<MessageInfo>;
12
12
  }
13
13
  export declare const SimplifyChatPageComponent: <T = any>(props: SimplifyChatPageProps<T>) => import("react/jsx-runtime").JSX.Element;
14
14
  export declare const SimplifyChatPage: <T = any>(props: SimplifyChatPageProps<T>) => import("react/jsx-runtime").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
+ import { styled } from "styled-components";
2
3
  import { ChatInput } from "../../ui/index.js";
3
4
  import { useChatClientContext, useMessageContext } from "../../context/index.js";
4
- import { styled } from "styled-components";
5
5
  const ChatSender = (props)=>{
6
6
  const { isRequesting, sendMessage } = useMessageContext();
7
7
  const { bubbleListRef } = useChatClientContext();
@@ -6,7 +6,9 @@ const ChatSplitter = (props)=>{
6
6
  const defaultSize = size?.default || '70%';
7
7
  const maxSize = size?.max || '80%';
8
8
  const minSize = size?.min || '60%';
9
+ const isOnlyOneVisible = left.visible && !right.visible || !left.visible && right.visible;
9
10
  return /*#__PURE__*/ jsxs(StyledSplitter, {
11
+ onlyOne: isOnlyOneVisible,
10
12
  children: [
11
13
  left.visible ? /*#__PURE__*/ jsx(Splitter.Panel, {
12
14
  defaultSize: defaultSize,
@@ -35,7 +37,9 @@ const ChatSplitter = (props)=>{
35
37
  const StyledSplitter = styled_components(Splitter)`
36
38
  height: 100%;
37
39
  background: rgb(240, 240, 240);
38
-
40
+ .ant-splitter-panel {
41
+ ${({ onlyOne })=>onlyOne ? 'flex-grow: 1 !important' : ''}
42
+ }
39
43
  .ant-splitter-bar-dragger::before {
40
44
  background: transparent !important;
41
45
  }
@@ -1,11 +1,13 @@
1
1
  import { ItemType } from 'antd/es/menu/interface';
2
2
  import { InfiniteListProps, InfiniteListRef, RenderActions } from '../../../../components/InfiniteList';
3
- export interface ConverstionListProps<T = any> {
3
+ export interface ConversationListProps<T = any> {
4
4
  rowKey: string;
5
5
  ref?: InfiniteListRef<T>;
6
6
  defaultActiveKey?: string;
7
7
  request: InfiniteListProps<T>['request'];
8
8
  menus?: (Omit<ItemType, 'onClick'> & {
9
+ key?: string;
10
+ label: string;
9
11
  onClick?: (item: T, index: number, actions: RenderActions<Record<string, any>>) => void;
10
12
  })[];
11
13
  onSelectConversation?: (data: T) => void;
@@ -17,5 +19,5 @@ type ItemData = {
17
19
  title: string;
18
20
  key: string;
19
21
  };
20
- export declare const ConversationList: <T extends ItemData = any>(props: ConverstionListProps<T>) => import("react/jsx-runtime").JSX.Element;
22
+ export declare const ConversationList: <T extends ItemData = any>(props: ConversationListProps<T>) => import("react/jsx-runtime").JSX.Element;
21
23
  export {};
@@ -89,6 +89,14 @@ const editor_EditorContent = (props)=>{
89
89
  const EditorContentStyled = styled_components(EditorContent)`
90
90
  .ProseMirror {
91
91
  outline: none;
92
+ p.is-empty::before {
93
+ content: attr(data-placeholder);
94
+ color: #999;
95
+ opacity: 1;
96
+ pointer-events: none;
97
+ float: left;
98
+ height: 0;
99
+ }
92
100
  p {
93
101
  margin: 2px 0;
94
102
  }
@@ -1,2 +1,3 @@
1
1
  export { EditorContent } from './editor';
2
2
  export type { EditorContentProps } from './editor';
3
+ export type { Editor as EditorInstance } from '@tiptap/react';
@@ -4,13 +4,17 @@ import { ListPageStore } from "./store.js";
4
4
  const ListPageContext = /*#__PURE__*/ createContext({});
5
5
  const ListPageProvider = (props)=>{
6
6
  const { state, request, children, initialValues, storageKey, floats } = props;
7
- const store = useMemo(()=>new ListPageStore({
7
+ const store = useMemo(()=>{
8
+ const store = new ListPageStore({
8
9
  state,
9
- initialValues,
10
- request,
11
10
  floats,
12
- storageKey
13
- }), []);
11
+ request,
12
+ storageKey,
13
+ initialValues
14
+ });
15
+ store.refreshTable();
16
+ return store;
17
+ }, []);
14
18
  return /*#__PURE__*/ jsx(ListPageContext.Provider, {
15
19
  value: store,
16
20
  children: children
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "listpage-next",
3
- "version": "0.0.182",
3
+ "version": "0.0.187",
4
4
  "description": "A React component library for creating filter forms with Ant Design",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",