@tianyr/schema-antd 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +158 -2
- package/dist/SchemaField.d.ts +15 -0
- package/dist/SchemaField.d.ts.map +1 -0
- package/dist/SchemaField.js +107 -0
- package/dist/SchemaField.js.map +1 -0
- package/dist/SchemaForm.d.ts +22 -0
- package/dist/SchemaForm.d.ts.map +1 -0
- package/dist/SchemaForm.js +19 -0
- package/dist/SchemaForm.js.map +1 -0
- package/dist/TableFooter.d.ts +38 -0
- package/dist/TableFooter.d.ts.map +1 -0
- package/dist/TableFooter.js +16 -0
- package/dist/TableFooter.js.map +1 -0
- package/dist/app-select/AppSelect.d.ts +3 -0
- package/dist/app-select/AppSelect.d.ts.map +1 -0
- package/dist/app-select/AppSelect.js +56 -0
- package/dist/app-select/AppSelect.js.map +1 -0
- package/dist/app-select/AppSelectDisplay.d.ts +3 -0
- package/dist/app-select/AppSelectDisplay.d.ts.map +1 -0
- package/dist/app-select/AppSelectDisplay.js +39 -0
- package/dist/app-select/AppSelectDisplay.js.map +1 -0
- package/dist/app-select/cache.d.ts +26 -0
- package/dist/app-select/cache.d.ts.map +1 -0
- package/dist/app-select/cache.js +82 -0
- package/dist/app-select/cache.js.map +1 -0
- package/dist/app-select/hooks.d.ts +56 -0
- package/dist/app-select/hooks.d.ts.map +1 -0
- package/dist/app-select/hooks.js +322 -0
- package/dist/app-select/hooks.js.map +1 -0
- package/dist/app-select/index.d.ts +7 -0
- package/dist/app-select/index.d.ts.map +1 -0
- package/dist/app-select/index.js +6 -0
- package/dist/app-select/index.js.map +1 -0
- package/dist/app-select/register.d.ts +2 -0
- package/dist/app-select/register.d.ts.map +1 -0
- package/dist/app-select/register.js +10 -0
- package/dist/app-select/register.js.map +1 -0
- package/dist/app-select/sources.d.ts +20 -0
- package/dist/app-select/sources.d.ts.map +1 -0
- package/dist/app-select/sources.js +59 -0
- package/dist/app-select/sources.js.map +1 -0
- package/dist/app-select/types.d.ts +68 -0
- package/dist/app-select/types.d.ts.map +1 -0
- package/dist/app-select/types.js +2 -0
- package/dist/app-select/types.js.map +1 -0
- package/dist/app-select/utils.d.ts +30 -0
- package/dist/app-select/utils.d.ts.map +1 -0
- package/dist/app-select/utils.js +76 -0
- package/dist/app-select/utils.js.map +1 -0
- package/dist/editable-table/EditableTable.d.ts +3 -0
- package/dist/editable-table/EditableTable.d.ts.map +1 -0
- package/dist/editable-table/EditableTable.js +499 -0
- package/dist/editable-table/EditableTable.js.map +1 -0
- package/dist/editable-table/dirty.d.ts +17 -0
- package/dist/editable-table/dirty.d.ts.map +1 -0
- package/dist/editable-table/dirty.js +72 -0
- package/dist/editable-table/dirty.js.map +1 -0
- package/dist/editable-table/index.d.ts +4 -0
- package/dist/editable-table/index.d.ts.map +1 -0
- package/dist/editable-table/index.js +3 -0
- package/dist/editable-table/index.js.map +1 -0
- package/dist/editable-table/types.d.ts +109 -0
- package/dist/editable-table/types.d.ts.map +1 -0
- package/dist/editable-table/types.js +2 -0
- package/dist/editable-table/types.js.map +1 -0
- package/dist/env.d.ts +3 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +11 -0
- package/dist/env.js.map +1 -0
- package/dist/form/FormRuntimeHost.d.ts +39 -0
- package/dist/form/FormRuntimeHost.d.ts.map +1 -0
- package/dist/form/FormRuntimeHost.js +184 -0
- package/dist/form/FormRuntimeHost.js.map +1 -0
- package/dist/form/SchemaFormField.d.ts +15 -0
- package/dist/form/SchemaFormField.d.ts.map +1 -0
- package/dist/form/SchemaFormField.js +142 -0
- package/dist/form/SchemaFormField.js.map +1 -0
- package/dist/form/derive.d.ts +33 -0
- package/dist/form/derive.d.ts.map +1 -0
- package/dist/form/derive.js +59 -0
- package/dist/form/derive.js.map +1 -0
- package/dist/form/namePath.d.ts +12 -0
- package/dist/form/namePath.d.ts.map +1 -0
- package/dist/form/namePath.js +33 -0
- package/dist/form/namePath.js.map +1 -0
- package/dist/full-editable-table/EditableCell.d.ts +12 -0
- package/dist/full-editable-table/EditableCell.d.ts.map +1 -0
- package/dist/full-editable-table/EditableCell.js +8 -0
- package/dist/full-editable-table/EditableCell.js.map +1 -0
- package/dist/full-editable-table/EditableRow.d.ts +8 -0
- package/dist/full-editable-table/EditableRow.d.ts.map +1 -0
- package/dist/full-editable-table/EditableRow.js +23 -0
- package/dist/full-editable-table/EditableRow.js.map +1 -0
- package/dist/full-editable-table/FullEditableTable.d.ts +3 -0
- package/dist/full-editable-table/FullEditableTable.d.ts.map +1 -0
- package/dist/full-editable-table/FullEditableTable.js +384 -0
- package/dist/full-editable-table/FullEditableTable.js.map +1 -0
- package/dist/full-editable-table/context.d.ts +4 -0
- package/dist/full-editable-table/context.d.ts.map +1 -0
- package/dist/full-editable-table/context.js +6 -0
- package/dist/full-editable-table/context.js.map +1 -0
- package/dist/full-editable-table/index.d.ts +3 -0
- package/dist/full-editable-table/index.d.ts.map +1 -0
- package/dist/full-editable-table/index.js +2 -0
- package/dist/full-editable-table/index.js.map +1 -0
- package/dist/full-editable-table/types.d.ts +95 -0
- package/dist/full-editable-table/types.d.ts.map +1 -0
- package/dist/full-editable-table/types.js +2 -0
- package/dist/full-editable-table/types.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/read.d.ts +14 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/read.js +151 -0
- package/dist/read.js.map +1 -0
- package/dist/registry.d.ts +24 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +49 -0
- package/dist/registry.js.map +1 -0
- package/dist/rowMerge.d.ts +2 -0
- package/dist/rowMerge.d.ts.map +1 -0
- package/dist/rowMerge.js +32 -0
- package/dist/rowMerge.js.map +1 -0
- package/dist/tableScroll.d.ts +10 -0
- package/dist/tableScroll.d.ts.map +1 -0
- package/dist/tableScroll.js +14 -0
- package/dist/tableScroll.js.map +1 -0
- package/dist/types.d.ts +128 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +60 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tianyr
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,159 @@
|
|
|
1
|
-
#
|
|
1
|
+
# schema-antd
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
基于 antd v5 的 Schema 驱动表单与可编辑表格。一份扁平的字段配置,同时用于普通表单、
|
|
4
|
+
单活动行编辑表格和全行常驻编辑表格,字段的显隐、禁用、校验、选项和联动都由配置描述。
|
|
5
|
+
|
|
6
|
+
- **不内置 antd**:`antd` / `react` 全部是 peer 依赖,产物只有 ESM 与类型声明
|
|
7
|
+
- **一份绑定层**:普通表单和两种表格的行复用同一个字段绑定,联动语义完全一致
|
|
8
|
+
- **可编辑列三态**:`true` 编辑、`'read'` 只读但跟随本行 Form(能看到联动带出的值)、`false` 直接读行记录
|
|
9
|
+
|
|
10
|
+
## 安装
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm i @tianyr/schema-antd
|
|
14
|
+
|
|
15
|
+
# 以下由你自己安装,本包不打包它们
|
|
16
|
+
npm i react react-dom antd dayjs @ant-design/icons
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
要求:React 18.2+、antd 5.20+、Node 18+(仅构建期)。只提供 ESM。
|
|
20
|
+
|
|
21
|
+
## 表单
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { SchemaForm } from '@tianyr/schema-antd'
|
|
25
|
+
import type { FormFieldSchema } from '@tianyr/schema-antd'
|
|
26
|
+
|
|
27
|
+
const schema: FormFieldSchema[] = [
|
|
28
|
+
{ type: 'InputNumber', name: 'qty', label: '数量', rules: [{ required: true, message: '请填写数量' }] },
|
|
29
|
+
{ type: 'InputNumber', name: 'price', label: '单价' },
|
|
30
|
+
{
|
|
31
|
+
type: 'InputNumber',
|
|
32
|
+
name: 'amount',
|
|
33
|
+
label: '金额',
|
|
34
|
+
// immediate: 不区分变更来源,初始化、回填、setData 都会重算(默认只在用户交互时执行)
|
|
35
|
+
linkage: [{
|
|
36
|
+
dependencies: ['qty', 'price'],
|
|
37
|
+
immediate: true,
|
|
38
|
+
handler: (ctx) => ctx.set('amount', Number(ctx.get('qty') ?? 0) * Number(ctx.get('price') ?? 0)),
|
|
39
|
+
}],
|
|
40
|
+
},
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
export function OrderForm() {
|
|
44
|
+
return <SchemaForm schema={schema} columns={2} onFinish={(values) => console.log(values)} />
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`dynamic.dependencies` 必须显式列出影响派生结果的所有字段,不做自动依赖收集:
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
{
|
|
52
|
+
type: 'Select',
|
|
53
|
+
name: 'city',
|
|
54
|
+
label: '城市',
|
|
55
|
+
dynamic: {
|
|
56
|
+
dependencies: ['province'],
|
|
57
|
+
disabled: (ctx) => !ctx.get('province'),
|
|
58
|
+
props: (ctx) => ({ options: CITIES[ctx.get('province') as string] ?? [] }),
|
|
59
|
+
},
|
|
60
|
+
linkage: [{
|
|
61
|
+
dependencies: ['province'],
|
|
62
|
+
handler: (ctx) => ctx.set('city', undefined),
|
|
63
|
+
}],
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 可编辑表格
|
|
68
|
+
|
|
69
|
+
两种形态,按数据量选:
|
|
70
|
+
|
|
71
|
+
| | `FullEditableTable` | `EditableTable` |
|
|
72
|
+
| --- | --- | --- |
|
|
73
|
+
| 状态 | 每行一个 `FormInstance`,全行常驻 | 单个 `FormInstance`,只挂活动行 |
|
|
74
|
+
| 适用 | 需要全行同时可编辑、逐行校验 | 行数大,单行编辑 + 行级保存 |
|
|
75
|
+
| 成本 | 约 **2.5ms / 单元格** | 约 **0.24ms / 单元格** |
|
|
76
|
+
|
|
77
|
+
实测(生产构建,100 行 × 10 列 = 1000 单元格,混合控件):全行常驻挂载约 2.5s,
|
|
78
|
+
单活动行约 0.24s。**超过约 1000 个可编辑单元格建议改用 `EditableTable`**,
|
|
79
|
+
150 行 × 15 列以上的场景没有实测数据。
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { FullEditableTable } from '@tianyr/schema-antd'
|
|
83
|
+
import type { EditableColumn } from '@tianyr/schema-antd'
|
|
84
|
+
|
|
85
|
+
const columns: EditableColumn<OrderRow>[] = [
|
|
86
|
+
{
|
|
87
|
+
title: '品名',
|
|
88
|
+
dataIndex: 'name',
|
|
89
|
+
editable: true,
|
|
90
|
+
field: { type: 'Input', name: 'name', rules: [{ required: true, message: '请填写品名' }] },
|
|
91
|
+
},
|
|
92
|
+
{ title: '数量', dataIndex: 'qty', editable: true, field: { type: 'InputNumber', name: 'qty' } },
|
|
93
|
+
// 'read':不参与校验,但跟随本行 Form,能显示 linkage 写进来的值
|
|
94
|
+
{ title: '金额', dataIndex: 'amount', editable: 'read', field: { type: 'InputNumber', name: 'amount' } },
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
<FullEditableTable<OrderRow> rowKey="id" columns={columns} initialRows={rows} />
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`editable` 三态别混:
|
|
101
|
+
|
|
102
|
+
- `true`:编辑控件,写进本行 Form,参与校验。「只读外观 + 仍要校验」用 `true` + `props.disabled`;
|
|
103
|
+
- `'read'`:挂字段但只读渲染,值跟随本行 Form,因此能看到 `events` / `linkage` 的带出值,**不参与校验**;
|
|
104
|
+
- `false` / 缺省:不挂字段,单元格直接读行记录,**看不到 Form 里的写值**。
|
|
105
|
+
|
|
106
|
+
`EditableTable` 的 `dataSource` 受控,新增/删除通过 `onSetData` 回传;泛型要显式传,
|
|
107
|
+
从 `dataSource` 推断会退化成 `object`:
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
<EditableTable<OrderRow>
|
|
111
|
+
rowKey="id"
|
|
112
|
+
columns={columns}
|
|
113
|
+
dataSource={rows}
|
|
114
|
+
onSave={async (next, original) => { await api.save(next); return next }}
|
|
115
|
+
onSetData={setRows}
|
|
116
|
+
createRow={() => ({ id: nanoid() })}
|
|
117
|
+
/>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## AppSelect
|
|
121
|
+
|
|
122
|
+
带搜索与回显分离的远程选择器。候选源在应用启动时注册一次:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { registerAppSelectSource } from '@tianyr/schema-antd'
|
|
126
|
+
|
|
127
|
+
registerAppSelectSource('product', {
|
|
128
|
+
kind: 'remote',
|
|
129
|
+
search: (keyword, params, signal) => api.searchProduct(keyword, params, signal),
|
|
130
|
+
resolve: (id, params, signal) => api.getProduct(id, params, signal),
|
|
131
|
+
requiredParams: ['companyId'], // 缺任一参数就不发请求
|
|
132
|
+
})
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
{ type: 'AppSelect', name: 'productId', label: '物料', props: { source: 'product', queryParams: { companyId } } }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
页面局部接口不必注册,直接把源对象传给 `dataSource`。
|
|
140
|
+
|
|
141
|
+
## 其他导出
|
|
142
|
+
|
|
143
|
+
`SchemaField`(单字段渲染,不含 name/label/rules)、`SchemaFormField`(唯一具名绑定层)、
|
|
144
|
+
`FormRuntimeHost` / `FormRuntimeHostProvider` / `useFormRuntimeHost`(联动运行时)、
|
|
145
|
+
`registerField` / `getFieldDefinition`(自定义控件类型)、`defaultRenderRead` / `renderReadValue`、
|
|
146
|
+
`mergeRowValues`,以及全部类型(`FormFieldSchema` / `EditableColumn` / `FullEditableTableRef` ……)。
|
|
147
|
+
|
|
148
|
+
字段的取值与写入只走 `ctx`:`ctx.get` / `ctx.getValues` / `ctx.set` / `ctx.setValues` / `ctx.clear`。
|
|
149
|
+
|
|
150
|
+
## 说明
|
|
151
|
+
|
|
152
|
+
- 只提供 ESM,不支持 CJS 消费方。
|
|
153
|
+
- 用 `import.meta.env.DEV` 判断开发态以输出告警,非 Vite 环境(如 SSR)下恒为 `false`,
|
|
154
|
+
不影响功能,只是少几条开发提示。
|
|
155
|
+
- `virtual` 不开放:虚拟滚动会卸载离屏行,全行常驻表格的行 Form 会随之销毁、输入丢失。
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
MIT
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AnyFieldSchema, FieldMode } from './types.js';
|
|
2
|
+
export interface SchemaFieldProps<TValue = unknown> {
|
|
3
|
+
schema: AnyFieldSchema<TValue>;
|
|
4
|
+
value?: TValue;
|
|
5
|
+
/** 统一为 (value, ...meta);Select/AppSelect 的 meta[0] 即选中项 */
|
|
6
|
+
onChange?: (value: TValue, ...meta: unknown[]) => void;
|
|
7
|
+
/** 高于 schema.mode */
|
|
8
|
+
mode?: FieldMode;
|
|
9
|
+
/** 运行态禁用,优先于 schema.props.disabled */
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
/** Form.Item 注入,用于 label 关联与 scrollToField */
|
|
12
|
+
id?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function SchemaField<TValue = unknown>({ schema, value, onChange, mode, disabled, id, }: SchemaFieldProps<TValue>): import("react").JSX.Element;
|
|
15
|
+
//# sourceMappingURL=SchemaField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SchemaField.d.ts","sourceRoot":"","sources":["../src/SchemaField.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,cAAc,EAGd,SAAS,EAEV,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,gBAAgB,CAAC,MAAM,GAAG,OAAO;IAChD,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IACvD,qBAAqB;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8CAA8C;IAC9C,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AA0CD,wBAAgB,WAAW,CAAC,MAAM,GAAG,OAAO,EAAE,EAC5C,MAAM,EACN,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,EAAE,GACH,EAAE,gBAAgB,CAAC,MAAM,CAAC,+BA8C1B"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { getFieldDefinition } from './registry.js';
|
|
3
|
+
import { IS_DEV } from './env.js';
|
|
4
|
+
import { renderReadValue } from './read.js';
|
|
5
|
+
/** 这三个属性由 SchemaField 独占,schema.props 中的同名项必须剔除 */
|
|
6
|
+
const CONTROLLED_KEYS = ['value', 'defaultValue', 'onChange'];
|
|
7
|
+
function Editor({ definition, schema, value, onChange, disabled, id }) {
|
|
8
|
+
const Component = definition.component;
|
|
9
|
+
const valuePropName = definition.valuePropName ?? 'value';
|
|
10
|
+
const componentProps = { ...schema.props };
|
|
11
|
+
for (const key of CONTROLLED_KEYS)
|
|
12
|
+
delete componentProps[key];
|
|
13
|
+
const finalDisabled = disabled ?? schema.props?.disabled;
|
|
14
|
+
const handleChange = (...args) => {
|
|
15
|
+
const [rawValue, ...meta] = args;
|
|
16
|
+
const nextValue = definition.getValueFromEvent
|
|
17
|
+
? definition.getValueFromEvent(...args)
|
|
18
|
+
: rawValue;
|
|
19
|
+
onChange?.(nextValue, ...meta);
|
|
20
|
+
};
|
|
21
|
+
return (_jsx(Component, { ...componentProps, [valuePropName]: value, onChange: handleChange, ...(finalDisabled === undefined ? {} : { disabled: finalDisabled }), ...(id === undefined ? {} : { id }) }));
|
|
22
|
+
}
|
|
23
|
+
export function SchemaField({ schema, value, onChange, mode, disabled, id, }) {
|
|
24
|
+
const finalMode = mode ?? schema.mode ?? 'edit';
|
|
25
|
+
// 局部自定义字段:必须在查 Registry 之前拦下,否则会落到「未注册类型」的报错路径
|
|
26
|
+
if (schema.type === 'Custom') {
|
|
27
|
+
return (_jsx(CustomField, { schema: schema, value: value, onChange: onChange, mode: finalMode, disabled: disabled, id: id }));
|
|
28
|
+
}
|
|
29
|
+
const definition = getFieldDefinition(schema.type);
|
|
30
|
+
if (finalMode === 'read') {
|
|
31
|
+
return (_jsx("span", { className: "schema-field schema-field-read", children: renderReadValue(value, schema, definition) }));
|
|
32
|
+
}
|
|
33
|
+
if (!definition) {
|
|
34
|
+
// 未注册类型是配置错误,开发态直接炸出来,生产态降级为可见提示
|
|
35
|
+
if (IS_DEV) {
|
|
36
|
+
throw new Error(`[schema] 未注册的字段类型:"${schema.type}"`);
|
|
37
|
+
}
|
|
38
|
+
return _jsxs("span", { className: "schema-field schema-field-error", children: ["\u672A\u77E5\u5B57\u6BB5\u7C7B\u578B\uFF1A", schema.type] });
|
|
39
|
+
}
|
|
40
|
+
// 编辑态不额外包 DOM,避免影响控件在表格单元格里的宽度与对齐
|
|
41
|
+
return (_jsx(Editor, { definition: definition, schema: schema, value: value, onChange: onChange, disabled: disabled, id: id }));
|
|
42
|
+
}
|
|
43
|
+
/** 只读空展示按 render 函数去重提示:schema 允许每帧重建,用函数引用才稳定 */
|
|
44
|
+
const warnedEmptyRead = new WeakSet();
|
|
45
|
+
// TValue 在这里无关紧要,只取用于报错的身份信息,避免被泛型不变量卡住
|
|
46
|
+
function describeCustomField(schema) {
|
|
47
|
+
const extra = schema;
|
|
48
|
+
const parts = [];
|
|
49
|
+
if (typeof extra.label === 'string' && extra.label)
|
|
50
|
+
parts.push(extra.label);
|
|
51
|
+
if (extra.name !== undefined)
|
|
52
|
+
parts.push(`name=${JSON.stringify(extra.name)}`);
|
|
53
|
+
return parts.length ? parts.join(' · ') : '未命名字段';
|
|
54
|
+
}
|
|
55
|
+
/** 配置错误:开发态直接抛,生产态给可见提示,不回退成普通输入 */
|
|
56
|
+
function failCustomField(schema, reason) {
|
|
57
|
+
const message = `[schema] 自定义字段配置错误(${reason}):${describeCustomField(schema)}`;
|
|
58
|
+
if (IS_DEV)
|
|
59
|
+
throw new Error(message);
|
|
60
|
+
return _jsxs("span", { className: "schema-field schema-field-error", children: ["\u81EA\u5B9A\u4E49\u5B57\u6BB5\u914D\u7F6E\u9519\u8BEF\uFF1A", reason] });
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 局部自定义字段:不查 Registry,把最终属性交给 schema.render。
|
|
64
|
+
*
|
|
65
|
+
* 属性组装(统一运行契约 §3.1):dynamic.props 已在上层合并,这里补
|
|
66
|
+
* disabled / id、剔除受控键,并保证 ctx.schema.props 与 ctx.props 同一引用。
|
|
67
|
+
*/
|
|
68
|
+
function CustomField({ schema, value, onChange, mode, disabled, id, }) {
|
|
69
|
+
if (typeof schema.render !== 'function') {
|
|
70
|
+
return failCustomField(schema, 'render 必须是函数');
|
|
71
|
+
}
|
|
72
|
+
const props = { ...(schema.props ?? {}) };
|
|
73
|
+
// schema.props 里的受控键不得覆盖表单注入的通道
|
|
74
|
+
for (const key of CONTROLLED_KEYS)
|
|
75
|
+
delete props[key];
|
|
76
|
+
// 表单级 disabled / dynamic.disabled 已合并成 SchemaField.disabled
|
|
77
|
+
if (disabled !== undefined)
|
|
78
|
+
props.disabled = disabled;
|
|
79
|
+
if (id !== undefined)
|
|
80
|
+
props.id = id;
|
|
81
|
+
const effectiveSchema = { ...schema, props };
|
|
82
|
+
if (mode === 'read') {
|
|
83
|
+
// 只读 JSX 不套文本 span:render 可能返回块级元素或 Portal
|
|
84
|
+
if (schema.renderRead) {
|
|
85
|
+
return _jsx(_Fragment, { children: schema.renderRead(value, effectiveSchema) });
|
|
86
|
+
}
|
|
87
|
+
const node = schema.render({ mode: 'read', value, props, schema: effectiveSchema });
|
|
88
|
+
if (IS_DEV && (node === null || node === undefined) && !warnedEmptyRead.has(schema.render)) {
|
|
89
|
+
warnedEmptyRead.add(schema.render);
|
|
90
|
+
console.warn(`[schema] 自定义字段的只读分支返回了 ${node === null ? 'null' : 'undefined'}:` +
|
|
91
|
+
`${describeCustomField(schema)}。若无 renderRead,请确认是有意不展示。`);
|
|
92
|
+
}
|
|
93
|
+
return _jsx(_Fragment, { children: node });
|
|
94
|
+
}
|
|
95
|
+
if (typeof onChange !== 'function') {
|
|
96
|
+
return failCustomField(schema, '编辑态缺少 onChange');
|
|
97
|
+
}
|
|
98
|
+
const ctx = {
|
|
99
|
+
mode: 'edit',
|
|
100
|
+
value,
|
|
101
|
+
onChange,
|
|
102
|
+
props,
|
|
103
|
+
schema: effectiveSchema,
|
|
104
|
+
};
|
|
105
|
+
return _jsx(_Fragment, { children: schema.render(ctx) });
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=SchemaField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SchemaField.js","sourceRoot":"","sources":["../src/SchemaField.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SchemaForm:用扁平 FormFieldSchema 组织一个普通表单。
|
|
3
|
+
*
|
|
4
|
+
* V1 只提供最小布局(columns + colSpan)与字段绑定;表单状态完全交给
|
|
5
|
+
* AntD FormInstance,不另维护一份受控整表 API。
|
|
6
|
+
*/
|
|
7
|
+
import type { ReactNode } from 'react';
|
|
8
|
+
import type { FormProps } from 'antd';
|
|
9
|
+
import type { AnyFormFieldSchema, FieldMode } from './types.js';
|
|
10
|
+
export interface SchemaFormProps extends Omit<FormProps, 'children'> {
|
|
11
|
+
schema: AnyFormFieldSchema[];
|
|
12
|
+
/** 多列布局,默认 1 */
|
|
13
|
+
columns?: number;
|
|
14
|
+
/** 表单级只读,强制覆盖字段 mode */
|
|
15
|
+
mode?: FieldMode;
|
|
16
|
+
/** 表单级禁用,永远优先于字段配置 */
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
/** 允许混用原生 Form.Item,共享同一个 FormInstance */
|
|
19
|
+
children?: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
export declare function SchemaForm({ schema, columns, mode, disabled, children, ...formProps }: SchemaFormProps): import("react").JSX.Element;
|
|
22
|
+
//# sourceMappingURL=SchemaForm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SchemaForm.d.ts","sourceRoot":"","sources":["../src/SchemaForm.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAKtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAE7D,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAClE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,gBAAgB;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,OAAW,EACX,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,GAAG,SAAS,EACb,EAAE,eAAe,+BA4BjB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Form } from 'antd';
|
|
3
|
+
import { FormRuntimeHostProvider } from './form/FormRuntimeHost.js';
|
|
4
|
+
import { SchemaFormField } from './form/SchemaFormField.js';
|
|
5
|
+
import { namePathKey } from './form/namePath.js';
|
|
6
|
+
export function SchemaForm({ schema, columns = 1, mode, disabled, children, ...formProps }) {
|
|
7
|
+
const [innerForm] = Form.useForm();
|
|
8
|
+
const form = formProps.form ?? innerForm;
|
|
9
|
+
const columnCount = Math.max(1, columns);
|
|
10
|
+
return (_jsx(Form, { ...formProps, form: form, children: _jsxs(FormRuntimeHostProvider, { form: form, children: [_jsx("div", { style: {
|
|
11
|
+
display: 'grid',
|
|
12
|
+
gridTemplateColumns: `repeat(${columnCount}, minmax(0, 1fr))`,
|
|
13
|
+
columnGap: 16,
|
|
14
|
+
}, children: schema.map((field) => {
|
|
15
|
+
const span = Math.min(Math.max(field.colSpan ?? 1, 1), columnCount);
|
|
16
|
+
return (_jsx("div", { style: span > 1 ? { gridColumn: `span ${span}` } : undefined, children: _jsx(SchemaFormField, { schema: field, mode: mode, disabled: disabled }) }, namePathKey(field.name)));
|
|
17
|
+
}) }), children] }) }));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=SchemaForm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SchemaForm.js","sourceRoot":"","sources":["../src/SchemaForm.tsx"],"names":[],"mappings":";AAOA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAe9C,MAAM,UAAU,UAAU,CAAC,EACzB,MAAM,EACN,OAAO,GAAG,CAAC,EACX,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,GAAG,SAAS,EACI;IAChB,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC;IACzC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAEzC,OAAO,CACL,KAAC,IAAI,OAAK,SAAS,EAAE,IAAI,EAAE,IAAI,YAC7B,MAAC,uBAAuB,IAAC,IAAI,EAAE,IAAI,aACjC,cACE,KAAK,EAAE;wBACL,OAAO,EAAE,MAAM;wBACf,mBAAmB,EAAE,UAAU,WAAW,mBAAmB;wBAC7D,SAAS,EAAE,EAAE;qBACd,YAEA,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;wBACpB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;wBACpE,OAAO,CACL,cAAmC,KAAK,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,YAC7F,KAAC,eAAe,IAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,GAAI,IAD1D,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAE3B,CACP,CAAC;oBACJ,CAAC,CAAC,GACE,EACL,QAAQ,IACe,GACrB,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 两个可编辑表格共用的工具条:新增按钮 + 插槽 + 批量删除。
|
|
3
|
+
*
|
|
4
|
+
* 位置由 placement 决定(默认底部;顶部与老家族 BatchEdit 的工具条一致),
|
|
5
|
+
* 按钮顺序固定为「新增 → 插槽 → 批量删除」:插槽紧跟新增按钮是既有约定,
|
|
6
|
+
* 批量删除是危险操作,放最右端避免误触。位置变化不改变顺序语义。
|
|
7
|
+
*
|
|
8
|
+
* 插槽是 render props:调用方拿到的 ctx 与 ref 上的行操作能力一致,
|
|
9
|
+
* 快捷录入之类的弹窗确认后可以直接 addRow,不必再额外持一份 ref。
|
|
10
|
+
*/
|
|
11
|
+
import type { ReactNode } from 'react';
|
|
12
|
+
import type { ToolbarPlacement } from './types.js';
|
|
13
|
+
/** 工具条能拿到的行操作能力;两边表格都提供 */
|
|
14
|
+
export interface TableFooterContext<T> {
|
|
15
|
+
addRow(record?: Partial<T>): void;
|
|
16
|
+
/** 当前已确认的数据快照,不含正在编辑的草稿 */
|
|
17
|
+
getDataSync(): T[];
|
|
18
|
+
}
|
|
19
|
+
interface TableFooterProps {
|
|
20
|
+
addText?: string;
|
|
21
|
+
/** 不传则不渲染新增按钮(只留插槽) */
|
|
22
|
+
onAdd?: () => void;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
extra?: ReactNode;
|
|
25
|
+
/** 批量删除文案,默认「批量删除」 */
|
|
26
|
+
batchDeleteText?: string;
|
|
27
|
+
/** 已选行数;为 0 时批量删除不可点 */
|
|
28
|
+
selectedCount?: number;
|
|
29
|
+
/** 不传则不渲染批量删除按钮(只留新增与插槽) */
|
|
30
|
+
onBatchDelete?: () => void;
|
|
31
|
+
/** 工具条位置,默认底部 */
|
|
32
|
+
placement?: ToolbarPlacement;
|
|
33
|
+
/** 内置按钮是否带图标(新增 / 批量删除),默认不带 */
|
|
34
|
+
showIcon?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export declare function TableFooter({ addText, onAdd, disabled, extra, batchDeleteText, selectedCount, onBatchDelete, placement, showIcon, }: TableFooterProps): import("react").JSX.Element | null;
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=TableFooter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TableFooter.d.ts","sourceRoot":"","sources":["../src/TableFooter.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAC;AAItD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,2BAA2B;AAC3B,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAClC,2BAA2B;IAC3B,WAAW,IAAI,CAAC,EAAE,CAAC;CACpB;AAED,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,sBAAsB;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wBAAwB;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4BAA4B;IAC5B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,iBAAiB;IACjB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,gCAAgC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAQD,wBAAgB,WAAW,CAAC,EAC1B,OAAc,EACd,KAAK,EACL,QAAQ,EACR,KAAK,EACL,eAAwB,EACxB,aAAiB,EACjB,aAAa,EACb,SAAoB,EACpB,QAAQ,GACT,EAAE,gBAAgB,sCAoClB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from 'antd';
|
|
3
|
+
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
|
4
|
+
const BASE_STYLE = {
|
|
5
|
+
display: 'flex',
|
|
6
|
+
alignItems: 'center',
|
|
7
|
+
gap: 8,
|
|
8
|
+
};
|
|
9
|
+
export function TableFooter({ addText = '新增', onAdd, disabled, extra, batchDeleteText = '批量删除', selectedCount = 0, onBatchDelete, placement = 'bottom', showIcon, }) {
|
|
10
|
+
if (!onAdd && !extra && !onBatchDelete)
|
|
11
|
+
return null;
|
|
12
|
+
return (_jsxs("div", { className: "schema-table-footer", style: placement === 'top'
|
|
13
|
+
? { ...BASE_STYLE, marginTop: 8, marginBottom: 8 }
|
|
14
|
+
: { ...BASE_STYLE, marginTop: 8 }, children: [onAdd ? (_jsx(Button, { type: "dashed", disabled: disabled, icon: showIcon ? _jsx(PlusOutlined, {}) : undefined, onClick: onAdd, children: addText })) : null, extra, onBatchDelete ? (_jsxs(Button, { danger: true, disabled: disabled || selectedCount === 0, icon: showIcon ? _jsx(DeleteOutlined, {}) : undefined, onClick: onBatchDelete, children: [batchDeleteText, selectedCount > 0 ? `(${selectedCount})` : ''] })) : null] }));
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=TableFooter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TableFooter.js","sourceRoot":"","sources":["../src/TableFooter.tsx"],"names":[],"mappings":";AAWA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AA6BjE,MAAM,UAAU,GAAkB;IAChC,OAAO,EAAE,MAAM;IACf,UAAU,EAAE,QAAQ;IACpB,GAAG,EAAE,CAAC;CACP,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,EAC1B,OAAO,GAAG,IAAI,EACd,KAAK,EACL,QAAQ,EACR,KAAK,EACL,eAAe,GAAG,MAAM,EACxB,aAAa,GAAG,CAAC,EACjB,aAAa,EACb,SAAS,GAAG,QAAQ,EACpB,QAAQ,GACS;IACjB,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,CAAC;IAEpD,OAAO,CACL,eACE,SAAS,EAAC,qBAAqB,EAC/B,KAAK,EACH,SAAS,KAAK,KAAK;YACjB,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,SAAS,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE;YAClD,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,SAAS,EAAE,CAAC,EAAE,aAGpC,KAAK,CAAC,CAAC,CAAC,CACP,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAC,YAAY,KAAG,CAAC,CAAC,CAAC,SAAS,EAC7C,OAAO,EAAE,KAAK,YAEb,OAAO,GACD,CACV,CAAC,CAAC,CAAC,IAAI,EACP,KAAK,EACL,aAAa,CAAC,CAAC,CAAC,CACf,MAAC,MAAM,IACL,MAAM,QACN,QAAQ,EAAE,QAAQ,IAAI,aAAa,KAAK,CAAC,EACzC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAC,cAAc,KAAG,CAAC,CAAC,CAAC,SAAS,EAC/C,OAAO,EAAE,aAAa,aAErB,eAAe,EACf,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,aAAa,GAAG,CAAC,CAAC,CAAC,EAAE,IACvC,CACV,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppSelect.d.ts","sourceRoot":"","sources":["../../src/app-select/AppSelect.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAa,cAAc,EAAuC,MAAM,SAAS,CAAC;AAG9F,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,+BAiF9C"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* AppSelect:AntD Select 之上的一层业务选择组件。
|
|
4
|
+
*
|
|
5
|
+
* 原则:内部始终用标量 ID 驱动 Select,绝不使用 labelInValue;
|
|
6
|
+
* 已选 ID 的解析与关键词搜索是两条独立逻辑。
|
|
7
|
+
*/
|
|
8
|
+
import { useMemo } from 'react';
|
|
9
|
+
import { Select } from 'antd';
|
|
10
|
+
import { useCandidateOptions, useResolvedSource, useSelectedOption } from './hooks.js';
|
|
11
|
+
import { isEmptyId, mergeOptions, normalizeOption } from './utils.js';
|
|
12
|
+
export function AppSelect(props) {
|
|
13
|
+
const { source, dataSource, options, queryParams, debounceMs, selectedOptions, value, onChange, valueMode = 'primitive', ...rest } = props;
|
|
14
|
+
const legacyValue = valueMode === 'object' ? value : undefined;
|
|
15
|
+
const rawValue = valueMode === 'object' ? legacyValue?.value : value;
|
|
16
|
+
// 空串与 null / undefined 等价,避免把 '' 当成一个有效 ID 传给 Select 或触发 resolve('')
|
|
17
|
+
const internalValue = isEmptyId(rawValue) ? undefined : rawValue;
|
|
18
|
+
const { sourceObj, sourceKey } = useResolvedSource(source, dataSource);
|
|
19
|
+
const { candidates, loading, search } = useCandidateOptions({
|
|
20
|
+
sourceObj,
|
|
21
|
+
sourceKey,
|
|
22
|
+
queryParams,
|
|
23
|
+
debounceMs,
|
|
24
|
+
});
|
|
25
|
+
const { option: selected, status } = useSelectedOption({
|
|
26
|
+
sourceObj,
|
|
27
|
+
sourceKey,
|
|
28
|
+
value: internalValue,
|
|
29
|
+
legacyLabel: legacyValue?.label,
|
|
30
|
+
selectedOptions,
|
|
31
|
+
candidates,
|
|
32
|
+
queryParams,
|
|
33
|
+
});
|
|
34
|
+
const mergedOptions = useMemo(() => mergeOptions(selected, options, candidates), [selected, options, candidates]);
|
|
35
|
+
const isRemote = sourceObj?.kind === 'remote';
|
|
36
|
+
const handleChange = (next, antOption) => {
|
|
37
|
+
const option = normalizeOption(antOption) ?? mergedOptions.find((item) => item.value === next);
|
|
38
|
+
const emit = onChange;
|
|
39
|
+
if (valueMode === 'object') {
|
|
40
|
+
emit?.(next === undefined || next === null ? undefined : { value: next, label: option?.label ?? '' }, option);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
emit?.(next ?? undefined, option);
|
|
44
|
+
};
|
|
45
|
+
return (_jsx(Select, { ...rest, labelInValue: false, showSearch: isRemote ? true : rest.showSearch, optionFilterProp: rest.optionFilterProp ?? 'label',
|
|
46
|
+
// 远程搜索由 dataSource 决定候选,不能让 AntD 在前端二次过滤
|
|
47
|
+
filterOption: isRemote ? false : rest.filterOption, options: mergedOptions, value: internalValue,
|
|
48
|
+
// 已选 ID 还在解析时也转圈,别让用户以为这个值没有名称
|
|
49
|
+
loading: loading || status === 'loading' || rest.loading, onChange: handleChange, onSearch: isRemote ? search : undefined, onDropdownVisibleChange: (open) => {
|
|
50
|
+
// 只有展开时才请求默认候选,避免挂载即发请求
|
|
51
|
+
if (open && isRemote && candidates.length === 0)
|
|
52
|
+
search('');
|
|
53
|
+
rest.onDropdownVisibleChange?.(open);
|
|
54
|
+
} }));
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=AppSelect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppSelect.js","sourceRoot":"","sources":["../../src/app-select/AppSelect.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { AppSelectDisplayProps } from './types.js';
|
|
2
|
+
export declare function AppSelectDisplay({ source, dataSource, value, valueMode, queryParams, selectedOptions, emptyText, }: AppSelectDisplayProps): import("react").JSX.Element;
|
|
3
|
+
//# sourceMappingURL=AppSelectDisplay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppSelectDisplay.d.ts","sourceRoot":"","sources":["../../src/app-select/AppSelectDisplay.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,qBAAqB,EAAyB,MAAM,SAAS,CAAC;AAc5E,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,UAAU,EACV,KAAK,EACL,SAAuB,EACvB,WAAW,EACX,eAAe,EACf,SAAsB,GACvB,EAAE,qBAAqB,+BAoBvB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* AppSelect 的轻量只读展示:复用同一套 label 解析,
|
|
4
|
+
* 不为了显示一个名称去挂载完整的可交互 Select。
|
|
5
|
+
*/
|
|
6
|
+
import { EMPTY_TEXT } from '../read.js';
|
|
7
|
+
import { useResolvedSource, useSelectedOption } from './hooks.js';
|
|
8
|
+
import { isEmptyId } from './utils.js';
|
|
9
|
+
/**
|
|
10
|
+
* 解析不到名称时仍显示原始 ID(绝不把 ID 伪装成名称),
|
|
11
|
+
* 但用 title 区分「正在查」「查不到」「请求失败」,避免回显失败被误认为业务值为空。
|
|
12
|
+
*/
|
|
13
|
+
const UNRESOLVED_TITLE = {
|
|
14
|
+
loading: '正在解析名称…',
|
|
15
|
+
missing: '未解析到名称,显示原始值',
|
|
16
|
+
blocked: '缺少必需的查询条件,暂无法解析名称',
|
|
17
|
+
error: '名称解析失败,显示原始值',
|
|
18
|
+
};
|
|
19
|
+
export function AppSelectDisplay({ source, dataSource, value, valueMode = 'primitive', queryParams, selectedOptions, emptyText = EMPTY_TEXT, }) {
|
|
20
|
+
const legacyValue = valueMode === 'object' ? value : undefined;
|
|
21
|
+
const rawValue = valueMode === 'object' ? legacyValue?.value : value;
|
|
22
|
+
const internalValue = isEmptyId(rawValue) ? undefined : rawValue;
|
|
23
|
+
const { sourceObj, sourceKey } = useResolvedSource(source, dataSource);
|
|
24
|
+
const { option, status } = useSelectedOption({
|
|
25
|
+
sourceObj,
|
|
26
|
+
sourceKey,
|
|
27
|
+
value: internalValue,
|
|
28
|
+
legacyLabel: legacyValue?.label,
|
|
29
|
+
selectedOptions,
|
|
30
|
+
queryParams,
|
|
31
|
+
});
|
|
32
|
+
if (internalValue === undefined)
|
|
33
|
+
return _jsx(_Fragment, { children: emptyText });
|
|
34
|
+
if (option)
|
|
35
|
+
return _jsx(_Fragment, { children: option.label });
|
|
36
|
+
const title = UNRESOLVED_TITLE[status];
|
|
37
|
+
return title ? _jsx("span", { title: title, children: String(internalValue) }) : _jsx(_Fragment, { children: String(internalValue) });
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=AppSelectDisplay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppSelectDisplay.js","sourceRoot":"","sources":["../../src/app-select/AppSelectDisplay.tsx"],"names":[],"mappings":";AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC;;;GAGG;AACH,MAAM,gBAAgB,GAAkD;IACtE,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,cAAc;IACvB,OAAO,EAAE,mBAAmB;IAC5B,KAAK,EAAE,cAAc;CACtB,CAAC;AAEF,MAAM,UAAU,gBAAgB,CAAC,EAC/B,MAAM,EACN,UAAU,EACV,KAAK,EACL,SAAS,GAAG,WAAW,EACvB,WAAW,EACX,eAAe,EACf,SAAS,GAAG,UAAU,GACA;IACtB,MAAM,WAAW,GAAG,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAE,KAAwC,CAAC,CAAC,CAAC,SAAS,CAAC;IACnG,MAAM,QAAQ,GAAG,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAE,KAAqC,CAAC;IACtG,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEjE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,iBAAiB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAEvE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAAC;QAC3C,SAAS;QACT,SAAS;QACT,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,WAAW,EAAE,KAAK;QAC/B,eAAe;QACf,WAAW;KACZ,CAAC,CAAC;IAEH,IAAI,aAAa,KAAK,SAAS;QAAE,OAAO,4BAAG,SAAS,GAAI,CAAC;IACzD,IAAI,MAAM;QAAE,OAAO,4BAAG,MAAM,CAAC,KAAK,GAAI,CAAC;IACvC,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,KAAK,CAAC,CAAC,CAAC,eAAM,KAAK,EAAE,KAAK,YAAG,MAAM,CAAC,aAAa,CAAC,GAAQ,CAAC,CAAC,CAAC,4BAAG,MAAM,CAAC,aAAa,CAAC,GAAI,CAAC;AACnG,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 已选 ID 的解析缓存。
|
|
3
|
+
*
|
|
4
|
+
* FullEditableTable V1 的硬前置:同源 in-flight 去重 + 轻量缓存。
|
|
5
|
+
* 只能减少重复 ID 的请求,不同 ID 仍是不同请求。
|
|
6
|
+
*/
|
|
7
|
+
import type { AppOption } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* 同一个 key 的并发调用共享一次请求;失败不缓存,下次可重试。
|
|
10
|
+
* 调用方各自的取消只影响自己的状态更新,不打断共享请求。
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveOptionWithCache(key: string, loader: () => Promise<AppOption | null>, ttl?: number): Promise<AppOption | null>;
|
|
13
|
+
/**
|
|
14
|
+
* 静态 / 字典集合的加载缓存。
|
|
15
|
+
* 每个 AppSelect 单元格各自 loadOptions 会在表格里重复打同一批字典请求,
|
|
16
|
+
* 因此按来源键共享;失败不缓存,下一次可重试。
|
|
17
|
+
*/
|
|
18
|
+
export declare function loadOptionsWithCache(key: string, loader: () => AppOption[] | Promise<AppOption[]>, ttl?: number): Promise<AppOption[]>;
|
|
19
|
+
/**
|
|
20
|
+
* 清掉某个注册源名下的缓存。
|
|
21
|
+
* 重新注册同名源(常见于开发态 HMR)时必须调用,否则会继续读到旧实现的结果。
|
|
22
|
+
*/
|
|
23
|
+
export declare function clearAppSelectCacheOfSource(name: string): void;
|
|
24
|
+
export declare function clearAppSelectCache(): void;
|
|
25
|
+
export declare function getAppSelectCacheSize(): number;
|
|
26
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/app-select/cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAazC;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,EACvC,GAAG,SAAc,GAChB,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAsB3B;AAUD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,SAAS,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,EAChD,GAAG,SAAc,GAChB,OAAO,CAAC,SAAS,EAAE,CAAC,CAqBtB;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAW9D;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C"}
|