@fe-free/core 2.5.4 → 2.5.6

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @fe-free/core
2
2
 
3
+ ## 2.5.6
4
+
5
+ ### Patch Changes
6
+
7
+ - feat: crud
8
+ - @fe-free/tool@2.5.6
9
+
10
+ ## 2.5.5
11
+
12
+ ### Patch Changes
13
+
14
+ - feat: crud
15
+ - @fe-free/tool@2.5.5
16
+
3
17
  ## 2.5.4
4
18
 
5
19
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fe-free/core",
3
- "version": "2.5.4",
3
+ "version": "2.5.6",
4
4
  "description": "",
5
5
  "main": "./src/index.ts",
6
6
  "author": "",
@@ -41,7 +41,7 @@
41
41
  "remark-gfm": "^4.0.1",
42
42
  "vanilla-jsoneditor": "^0.23.1",
43
43
  "zustand": "^4.5.4",
44
- "@fe-free/tool": "2.5.4"
44
+ "@fe-free/tool": "2.5.6"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "@ant-design/pro-components": "2.8.9",
@@ -2,6 +2,4 @@ export { CRUD } from './crud';
2
2
  export { OperateDelete, useDelete } from './crud_delete';
3
3
  export { CRUDDetail } from './crud_detail';
4
4
  export type { CRUDDetailProps } from './crud_detail';
5
- export { CRUDOfSimple } from './crud_of_simple';
6
- export type { CRUDOfSimpleProps } from './crud_of_simple';
7
5
  export type { CRUDMethods, CRUDProps } from './types';
@@ -8,39 +8,3 @@
8
8
  }
9
9
  }
10
10
  }
11
-
12
- .fec-crud-of-simple {
13
- .ant-pro-table-list-toolbar {
14
- border-bottom: 1px solid #f0f0f0;
15
- }
16
-
17
- &.fec-crud-of-simple-hover-show {
18
- .ant-table-cell-fix-right {
19
- position: absolute !important;
20
- display: none;
21
- }
22
-
23
- .ant-table-row {
24
- &:hover {
25
- .ant-table-cell-fix-right {
26
- display: block;
27
- }
28
- }
29
- }
30
- }
31
-
32
- &.fec-crud-of-simple-search-width-full {
33
- .ant-pro-table-list-toolbar-container {
34
- justify-content: unset;
35
-
36
- .ant-pro-table-list-toolbar-right {
37
- justify-content: unset;
38
-
39
- & > div {
40
- flex: 1;
41
- margin-right: 8px;
42
- }
43
- }
44
- }
45
- }
46
- }
@@ -1,16 +1,28 @@
1
1
  import { ProFormText } from '@ant-design/pro-components';
2
- import { CRUDOfSimple } from '@fe-free/core';
2
+ import { CRUDOfList } from '@fe-free/core';
3
3
  import type { Meta, StoryObj } from '@storybook/react-vite';
4
- import { fakeCreate, fakeDeleteByRecord, fakeRequest } from './demo/data';
4
+ import { fakeCreate, fakeDeleteByRecord, fakeRequest } from '../crud/demo/data';
5
5
 
6
- const meta: Meta<typeof CRUDOfSimple> = {
7
- title: '@fe-free/core/CRUDOfSimple',
8
- component: CRUDOfSimple,
6
+ const meta: Meta<typeof CRUDOfList> = {
7
+ title: '@fe-free/core/CRUDOfList',
8
+ component: CRUDOfList,
9
9
  tags: ['autodocs'],
10
+ parameters: {
11
+ docs: {
12
+ description: {
13
+ component: `
14
+ CRUDOfList 组件。(简洁的列表形态的 CRUD 组件)
15
+ - 隐藏 label
16
+ - 搜索表单按钮一行
17
+ - 移除卡片布局
18
+ `,
19
+ },
20
+ },
21
+ },
10
22
  decorators: [
11
23
  (Story) => {
12
24
  return (
13
- <div className="c-border h-[500px] w-[300px] overflow-x-auto">
25
+ <div className="c-border h-[500px] w-[300px] overflow-y-auto">
14
26
  <Story />
15
27
  </div>
16
28
  );
@@ -19,27 +31,25 @@ const meta: Meta<typeof CRUDOfSimple> = {
19
31
  };
20
32
 
21
33
  export default meta;
22
- type Story = StoryObj<typeof CRUDOfSimple>;
34
+ type Story = StoryObj<typeof CRUDOfList>;
23
35
 
24
- // 基础用法
25
- export const Normal: Story = {
36
+ export const Basic: Story = {
26
37
  render: () => {
27
38
  const columns = [
28
39
  {
29
40
  title: '名字(省略)',
30
41
  dataIndex: 'name',
31
- search: true,
42
+ // search: true,
32
43
  ellipsis: true,
33
44
  },
34
45
  ];
35
46
 
36
47
  return (
37
- <CRUDOfSimple
38
- actions={['create', 'delete']}
48
+ <CRUDOfList
49
+ actions={[]}
39
50
  tableProps={{
40
51
  columns,
41
52
  request: fakeRequest,
42
- pagination: false,
43
53
  }}
44
54
  requestDeleteByRecord={fakeDeleteByRecord}
45
55
  deleteProps={{
@@ -47,13 +57,7 @@ export const Normal: Story = {
47
57
  }}
48
58
  detailForm={() => (
49
59
  <>
50
- <ProFormText
51
- name="name"
52
- label="名字"
53
- required
54
- rules={[{ required: true }]}
55
- extra="extra extra extra extra"
56
- />
60
+ <ProFormText name="name" label="名字" required rules={[{ required: true }]} />
57
61
  </>
58
62
  )}
59
63
  requestCreateByValues={fakeCreate}
@@ -74,12 +78,11 @@ export const WithSearch: Story = {
74
78
  ];
75
79
 
76
80
  return (
77
- <CRUDOfSimple
78
- actions={['create', 'delete']}
81
+ <CRUDOfList
82
+ actions={['delete']}
79
83
  tableProps={{
80
84
  columns,
81
85
  request: fakeRequest,
82
- pagination: false,
83
86
  }}
84
87
  requestDeleteByRecord={fakeDeleteByRecord}
85
88
  deleteProps={{
@@ -87,26 +90,16 @@ export const WithSearch: Story = {
87
90
  }}
88
91
  detailForm={() => (
89
92
  <>
90
- <ProFormText
91
- name="name"
92
- label="名字"
93
- required
94
- rules={[{ required: true }]}
95
- extra="extra extra extra extra"
96
- />
93
+ <ProFormText name="name" label="名字" required rules={[{ required: true }]} />
97
94
  </>
98
95
  )}
99
96
  requestCreateByValues={fakeCreate}
100
- simpleSearchProps={{
101
- name: 'name',
102
- widthFull: true,
103
- }}
104
97
  />
105
98
  );
106
99
  },
107
100
  };
108
101
 
109
- export const HoverShow: Story = {
102
+ export const WithCreateDelete: Story = {
110
103
  render: () => {
111
104
  const columns = [
112
105
  {
@@ -118,12 +111,11 @@ export const HoverShow: Story = {
118
111
  ];
119
112
 
120
113
  return (
121
- <CRUDOfSimple
114
+ <CRUDOfList
122
115
  actions={['create', 'delete']}
123
116
  tableProps={{
124
117
  columns,
125
118
  request: fakeRequest,
126
- pagination: false,
127
119
  }}
128
120
  requestDeleteByRecord={fakeDeleteByRecord}
129
121
  deleteProps={{
@@ -131,40 +123,31 @@ export const HoverShow: Story = {
131
123
  }}
132
124
  detailForm={() => (
133
125
  <>
134
- <ProFormText
135
- name="name"
136
- label="名字"
137
- required
138
- rules={[{ required: true }]}
139
- extra="extra extra extra extra"
140
- />
126
+ <ProFormText name="name" label="名字" required rules={[{ required: true }]} />
141
127
  </>
142
128
  )}
143
129
  requestCreateByValues={fakeCreate}
144
- simpleOperateHoverShow
145
130
  />
146
131
  );
147
132
  },
148
133
  };
149
134
 
150
- export const JustSearch: Story = {
135
+ export const NoSearch: Story = {
151
136
  render: () => {
152
137
  const columns = [
153
138
  {
154
139
  title: '名字(省略)',
155
140
  dataIndex: 'name',
156
- search: true,
157
141
  ellipsis: true,
158
142
  },
159
143
  ];
160
144
 
161
145
  return (
162
- <CRUDOfSimple
163
- actions={['delete']}
146
+ <CRUDOfList
147
+ actions={['create', 'delete']}
164
148
  tableProps={{
165
149
  columns,
166
150
  request: fakeRequest,
167
- pagination: false,
168
151
  }}
169
152
  requestDeleteByRecord={fakeDeleteByRecord}
170
153
  deleteProps={{
@@ -172,20 +155,10 @@ export const JustSearch: Story = {
172
155
  }}
173
156
  detailForm={() => (
174
157
  <>
175
- <ProFormText
176
- name="name"
177
- label="名字"
178
- required
179
- rules={[{ required: true }]}
180
- extra="extra extra extra extra"
181
- />
158
+ <ProFormText name="name" label="名字" required rules={[{ required: true }]} />
182
159
  </>
183
160
  )}
184
161
  requestCreateByValues={fakeCreate}
185
- simpleSearchProps={{
186
- name: 'name',
187
- widthFull: true,
188
- }}
189
162
  />
190
163
  );
191
164
  },
@@ -2,32 +2,26 @@ import { useDebounce } from 'ahooks';
2
2
  import { Input } from 'antd';
3
3
  import classNames from 'classnames';
4
4
  import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
5
- import { CRUD } from './crud';
6
- import type { CRUDMethods, CRUDProps } from './types';
5
+ import type { CRUDMethods, CRUDProps } from '../crud';
6
+ import { CRUD } from '../crud';
7
+ import './style.scss';
7
8
 
8
- interface CRUDOfSimpleProps<
9
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
10
+ interface CRUDOfListProps<
9
11
  DataSource extends Record<string, any> = any,
10
12
  Key extends string | number = string,
11
13
  > extends CRUDProps<DataSource, Key> {
12
- simpleOperateHoverShow?: boolean;
13
- // 传才开启搜索
14
- simpleSearchProps?: {
15
- /** 搜索项的名称,默认 keywords */
16
- name: string;
17
- /** 搜索项的 placeholder,默认 请输入 */
18
- placeholder?: string;
19
- /** 占满宽度 */
20
- widthFull?: boolean;
21
- };
14
+ // nothing
22
15
  }
23
16
 
24
17
  function useTips(props) {
25
- const { columns } = props;
26
-
27
18
  useEffect(() => {
28
- const hasSearchColumn = columns?.find((column) => column.search);
29
- if (hasSearchColumn) {
30
- console.warn('CRUDOfSimple 的 columns 中不能有 search 为 true 的列');
19
+ const count = props.tableProps.columns?.filter((column) => column.search).length;
20
+ if (!count) {
21
+ console.warn('CRUDOfList 的 columns 中至少有一个 search 为 true 的列');
22
+ }
23
+ if (count > 1) {
24
+ console.warn('CRUDOfList 的 columns 中只能有一个 search 为 true 的列');
31
25
  }
32
26
  }, []);
33
27
  }
@@ -48,14 +42,18 @@ function SearchRender(props: {
48
42
  );
49
43
  }
50
44
 
51
- function CRUDOfSimpleComponent(props: CRUDOfSimpleProps, ref: React.ForwardedRef<CRUDMethods>) {
52
- const { simpleSearchProps, tableProps, simpleOperateHoverShow, ...rest } = props;
53
-
45
+ function CRUDOfListComponent(props: CRUDOfListProps, ref: React.ForwardedRef<CRUDMethods>) {
54
46
  useTips(props);
55
- const [searchValue, setSearchValue] = useState<string>('');
56
47
 
48
+ const { tableProps, ...rest } = props;
49
+
50
+ const [searchValue, setSearchValue] = useState<string>('');
57
51
  const debouncedSearchValue = useDebounce(searchValue, { wait: 300 });
58
52
 
53
+ const searchDataIndex = useMemo(() => {
54
+ return tableProps.columns?.find((column) => column.search)?.dataIndex;
55
+ }, [tableProps.columns]);
56
+
59
57
  const newColumns = useMemo(() => {
60
58
  return (tableProps.columns || []).map((column) => ({
61
59
  ...column,
@@ -66,56 +64,49 @@ function CRUDOfSimpleComponent(props: CRUDOfSimpleProps, ref: React.ForwardedRef
66
64
  const toolBarRender = useCallback(
67
65
  (...args) => {
68
66
  return [
69
- simpleSearchProps && (
70
- <SearchRender
71
- key="search-input"
72
- placeholder={simpleSearchProps.placeholder}
73
- value={searchValue}
74
- onChange={(value) => setSearchValue(value)}
75
- />
76
- ),
67
+ <div key="search-input-container" className="w-full">
68
+ {searchDataIndex && (
69
+ <SearchRender value={searchValue} onChange={(value) => setSearchValue(value)} />
70
+ )}
71
+ </div>,
77
72
  // @ts-ignore
78
73
  ...(tableProps.toolBarRender ? tableProps.toolBarRender(...args) : []),
79
74
  ];
80
75
  },
81
- [searchValue, simpleSearchProps, tableProps],
76
+ [searchValue, searchDataIndex, tableProps],
82
77
  );
83
78
 
84
79
  const newParams = useMemo(() => {
85
- if (!simpleSearchProps) {
86
- return tableProps.params;
87
- }
88
-
89
80
  return {
90
- ...tableProps.params,
91
- [simpleSearchProps.name]: debouncedSearchValue,
81
+ ...(tableProps.params || {}),
82
+ [searchDataIndex]: debouncedSearchValue,
92
83
  };
93
- }, [debouncedSearchValue, simpleSearchProps, tableProps.params]);
84
+ }, [debouncedSearchValue, searchDataIndex, tableProps.params]);
94
85
 
95
86
  return (
96
87
  <div
97
- className={classNames('fec-crud-of-simple', {
98
- 'fec-crud-of-simple-hover-show': simpleOperateHoverShow,
99
- 'fec-crud-of-simple-search-width-full': simpleSearchProps?.widthFull,
88
+ className={classNames('fec-crud-of-list', {
89
+ // 先这样实现
90
+ 'fec-crud-of-list-no-toolbar': !searchDataIndex && !props.actions.includes('create'),
100
91
  })}
101
92
  >
102
93
  <CRUD
103
94
  ref={ref}
104
95
  {...rest}
105
96
  tableProps={{
106
- ...tableProps,
107
- params: newParams,
108
97
  cardBordered: false,
109
98
  showHeader: false,
110
99
  ghost: true,
111
- columns: newColumns,
112
- toolBarRender,
113
100
  // 简单的隐藏搜索栏
114
101
  search: false,
102
+ pagination: false,
103
+ ...tableProps,
104
+ params: newParams,
105
+ columns: newColumns,
106
+ toolBarRender,
115
107
  }}
116
108
  operateColumnProps={{
117
- // hoverShow 情况下,默认 width 1
118
- width: simpleOperateHoverShow ? 1 : undefined,
109
+ width: 1,
119
110
  ...props.operateColumnProps,
120
111
  }}
121
112
  />
@@ -123,12 +114,12 @@ function CRUDOfSimpleComponent(props: CRUDOfSimpleProps, ref: React.ForwardedRef
123
114
  );
124
115
  }
125
116
 
126
- const CRUDOfSimple = forwardRef(CRUDOfSimpleComponent) as <
117
+ const CRUDOfList = forwardRef(CRUDOfListComponent) as <
127
118
  DataSource extends Record<string, any> = any,
128
119
  Key extends string | number = string,
129
120
  >(
130
- props: CRUDOfSimpleProps<DataSource, Key> & { ref?: React.ForwardedRef<CRUDMethods> },
121
+ props: CRUDOfListProps<DataSource, Key> & { ref?: React.ForwardedRef<CRUDMethods> },
131
122
  ) => JSX.Element;
132
123
 
133
- export { CRUDOfSimple };
134
- export type { CRUDOfSimpleProps };
124
+ export { CRUDOfList };
125
+ export type { CRUDOfListProps };
@@ -0,0 +1,37 @@
1
+ .fec-crud-of-list {
2
+ .ant-pro-table-list-toolbar {
3
+ border-bottom: 1px solid #f0f0f0;
4
+ }
5
+
6
+ .ant-table-cell-fix-right {
7
+ position: absolute !important;
8
+ display: none;
9
+ }
10
+
11
+ .ant-table-row {
12
+ &:hover {
13
+ .ant-table-cell-fix-right {
14
+ display: block;
15
+ }
16
+ }
17
+ }
18
+
19
+ .ant-pro-table-list-toolbar-container {
20
+ justify-content: unset;
21
+
22
+ .ant-pro-table-list-toolbar-right {
23
+ justify-content: unset;
24
+
25
+ & > div {
26
+ flex: 1;
27
+ margin-right: 8px;
28
+ }
29
+ }
30
+ }
31
+
32
+ &.fec-crud-of-list-no-toolbar {
33
+ .ant-pro-table-list-toolbar-container {
34
+ padding-block: 0;
35
+ }
36
+ }
37
+ }
@@ -25,8 +25,7 @@ CRUDOfPure 组件。(更简洁的 CRUD 组件)
25
25
  export default meta;
26
26
  type Story = StoryObj<typeof CRUDOfPure>;
27
27
 
28
- // 基础用法
29
- export const Normal: Story = {
28
+ export const Basic: Story = {
30
29
  render: () => {
31
30
  const columns = [
32
31
  {
@@ -88,3 +87,117 @@ export const Normal: Story = {
88
87
  );
89
88
  },
90
89
  };
90
+
91
+ export const WithCreate: Story = {
92
+ render: () => {
93
+ const columns = [
94
+ {
95
+ title: 'id',
96
+ dataIndex: 'id',
97
+ search: true,
98
+ },
99
+ {
100
+ title: '名字(省略)',
101
+ dataIndex: 'name',
102
+ search: true,
103
+ ellipsis: true,
104
+ },
105
+ {
106
+ title: 'city',
107
+ dataIndex: 'city',
108
+ },
109
+ {
110
+ title: 'area',
111
+ dataIndex: 'area',
112
+ },
113
+ ];
114
+
115
+ return (
116
+ <CRUDOfPure
117
+ actions={['create', 'delete']}
118
+ tableProps={{
119
+ columns,
120
+ request: fakeRequest,
121
+ pagination: false,
122
+ search: {
123
+ optionRender: (_, __, dom) => {
124
+ return [
125
+ ...dom,
126
+ <Button key="1" type="primary" className="ml-2">
127
+ 额外的按钮
128
+ </Button>,
129
+ ];
130
+ },
131
+ },
132
+ }}
133
+ requestDeleteByRecord={fakeDeleteByRecord}
134
+ deleteProps={{
135
+ nameIndex: 'id',
136
+ }}
137
+ detailForm={() => (
138
+ <>
139
+ <ProFormText
140
+ name="name"
141
+ label="名字"
142
+ required
143
+ rules={[{ required: true }]}
144
+ extra="extra extra extra extra"
145
+ />
146
+ </>
147
+ )}
148
+ requestCreateByValues={fakeCreate}
149
+ />
150
+ );
151
+ },
152
+ };
153
+
154
+ export const NoSearch: Story = {
155
+ render: () => {
156
+ const columns = [
157
+ {
158
+ title: 'id',
159
+ dataIndex: 'id',
160
+ },
161
+ {
162
+ title: '名字(省略)',
163
+ dataIndex: 'name',
164
+ ellipsis: true,
165
+ },
166
+ {
167
+ title: 'city',
168
+ dataIndex: 'city',
169
+ },
170
+ {
171
+ title: 'area',
172
+ dataIndex: 'area',
173
+ },
174
+ ];
175
+
176
+ return (
177
+ <CRUDOfPure
178
+ actions={['create', 'delete']}
179
+ tableProps={{
180
+ columns,
181
+ request: fakeRequest,
182
+ pagination: false,
183
+ }}
184
+ requestDeleteByRecord={fakeDeleteByRecord}
185
+ deleteProps={{
186
+ nameIndex: 'id',
187
+ }}
188
+ detailForm={() => (
189
+ <>
190
+ <ProFormText
191
+ name="name"
192
+ label="名字"
193
+ required
194
+ rules={[{ required: true }]}
195
+ extra="extra extra extra extra"
196
+ />
197
+ </>
198
+ )}
199
+ requestCreateByValues={fakeCreate}
200
+ />
201
+ );
202
+ },
203
+ };
@@ -1,5 +1,5 @@
1
1
  import classNames from 'classnames';
2
- import { forwardRef } from 'react';
2
+ import { forwardRef, useMemo } from 'react';
3
3
  import type { CRUDMethods, CRUDProps } from '../crud';
4
4
  import { CRUD } from '../crud';
5
5
  import './style.scss';
@@ -33,8 +33,16 @@ function CRUDOfPureComponent(props: CRUDOfPureProps, ref: React.ForwardedRef<CRU
33
33
  return column;
34
34
  });
35
35
 
36
+ const noSearch = useMemo(() => {
37
+ return !props.tableProps.columns?.find((column) => column.search);
38
+ }, [props.tableProps.columns]);
39
+
36
40
  return (
37
- <div className={classNames('fec-crud-of-pure')}>
41
+ <div
42
+ className={classNames('fec-crud-of-pure', {
43
+ 'fec-crud-of-pure-no-search': noSearch,
44
+ })}
45
+ >
38
46
  <CRUD
39
47
  ref={ref}
40
48
  {...props}
@@ -40,7 +40,12 @@
40
40
  }
41
41
 
42
42
  .ant-pro-table-list-toolbar-container {
43
- padding-block: 0;
44
- padding-block-end: 8px;
43
+ padding-block: 0 8px;
44
+ }
45
+
46
+ &.fec-crud-of-pure-no-search {
47
+ .ant-pro-table-list-toolbar-container {
48
+ padding-block-start: 8px;
49
+ }
45
50
  }
46
51
  }
package/src/index.ts CHANGED
@@ -6,8 +6,10 @@ export { LoadingButton } from './button';
6
6
  export { Copy } from './copy';
7
7
  export type { CopyProps } from './copy';
8
8
  export { CoreApp } from './core_app';
9
- export { CRUD, CRUDDetail, CRUDOfSimple, OperateDelete, useDelete } from './crud';
10
- export type { CRUDDetailProps, CRUDMethods, CRUDOfSimpleProps, CRUDProps } from './crud';
9
+ export { CRUD, CRUDDetail, OperateDelete, useDelete } from './crud';
10
+ export type { CRUDDetailProps, CRUDMethods, CRUDProps } from './crud';
11
+ export { CRUDOfList } from './crud_of_list';
12
+ export type { CRUDOfListProps } from './crud_of_list';
11
13
  export { CRUDOfPure } from './crud_of_pure';
12
14
  export type { CRUDOfPureProps } from './crud_of_pure';
13
15
  export { Editor } from './editor';
@@ -38,19 +38,28 @@ function Table<
38
38
  const hasSearch = !!newColumns?.find((column) => column.search);
39
39
 
40
40
  let newSearch: any = undefined;
41
+ // 如果有搜索,则使用 search 的配置
41
42
  if (hasSearch) {
42
43
  newSearch = {
43
44
  labelWidth: 'auto',
44
45
  defaultCollapsed: false,
45
46
  ...search,
46
47
  };
47
- } else if (search === false) {
48
- newSearch = false;
49
- } else {
48
+ }
49
+ // 如果是个对象
50
+ else if (typeof search === 'object') {
50
51
  newSearch = {
51
52
  ...search,
52
53
  };
53
54
  }
55
+ // 明确 search false 的情况,这样外部可以控制搜索的显示
56
+ else if (search === false) {
57
+ newSearch = false;
58
+ }
59
+ // 最后兜底 false
60
+ else {
61
+ newSearch = false;
62
+ }
54
63
 
55
64
  return (
56
65
  <ProTable<DataSource, Params>