@wordrhyme/auto-crud 1.12.2 → 1.13.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/README.md +25 -11
- package/dist/index.cjs +221 -103
- package/dist/index.d.cts +61 -48
- package/dist/index.d.ts +61 -48
- package/dist/index.js +222 -105
- package/dist/styles.css +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -278,6 +278,8 @@ interface AutoCrudTableProps<TSchema> {
|
|
|
278
278
|
form?: {
|
|
279
279
|
overrides?: Record<string, any>; // 表单覆盖配置
|
|
280
280
|
columns?: number; // 表单列数
|
|
281
|
+
labelAlign?: 'left' | 'top' | 'right'; // 默认 top;left/right 为左右布局及标签文字对齐
|
|
282
|
+
labelWidth?: number | string; // 左右布局的标签宽度,数字单位为 px
|
|
281
283
|
};
|
|
282
284
|
/**
|
|
283
285
|
* 行操作配置,或统一配置 toolbar/row/batch。
|
|
@@ -1509,27 +1511,39 @@ function CustomTable({ data }) {
|
|
|
1509
1511
|
### 使用 AutoForm 组件
|
|
1510
1512
|
|
|
1511
1513
|
```typescript
|
|
1512
|
-
import { AutoForm
|
|
1513
|
-
import { createForm } from "@formily/core";
|
|
1514
|
+
import { AutoForm } from "@wordrhyme/auto-crud";
|
|
1514
1515
|
|
|
1515
1516
|
function CustomForm() {
|
|
1516
|
-
const form = createForm();
|
|
1517
|
-
const formSchema = createFormSchema(taskSchema, {
|
|
1518
|
-
exclude: ["id", "createdAt"],
|
|
1519
|
-
layout: "grid",
|
|
1520
|
-
gridColumns: 2,
|
|
1521
|
-
});
|
|
1522
|
-
|
|
1523
1517
|
return (
|
|
1524
1518
|
<AutoForm
|
|
1525
|
-
|
|
1526
|
-
|
|
1519
|
+
schema={taskSchema}
|
|
1520
|
+
gridColumns={2}
|
|
1527
1521
|
onSubmit={(values) => console.log(values)}
|
|
1528
1522
|
/>
|
|
1529
1523
|
);
|
|
1530
1524
|
}
|
|
1531
1525
|
```
|
|
1532
1526
|
|
|
1527
|
+
详情使用同一条 Formily 渲染链路,通过 `mode="view"` 启用 `readPretty`,无需传入 `onSubmit`,也不会显示提交按钮:
|
|
1528
|
+
|
|
1529
|
+
```tsx
|
|
1530
|
+
<AutoForm
|
|
1531
|
+
mode="view"
|
|
1532
|
+
schema={taskSchema}
|
|
1533
|
+
initialValues={selectedTask}
|
|
1534
|
+
fields={fields}
|
|
1535
|
+
gridColumns={2}
|
|
1536
|
+
/>
|
|
1537
|
+
```
|
|
1538
|
+
|
|
1539
|
+
创建、编辑排除 ID 和审计托管字段;详情保留 ID、创建时间和更新时间。`form: false` 和字段级 `form['x-hidden']` 只影响创建、编辑;全局 `hidden` 和 `permissions.deny` 仍限制详情字段。其他表单覆盖配置、布局、scope 和选项标签继续共用。
|
|
1540
|
+
|
|
1541
|
+
内置字段提供阅读态映射;通过 `components.register()` 注册的自定义组件应使用 Formily `mapReadPretty` 实现自己的阅读态。`AutoCrudTable` 详情仍展示当前选中记录,不会额外请求单条接口。
|
|
1542
|
+
|
|
1543
|
+
详情默认单列,列数由 `AutoCrudTable` 的 `form.columns` 或 `AutoForm` 的 `gridColumns` 控制,使用浅色标签和宽松间距;长文本、数组和对象默认占满整行,字段 `gridSpan` 可指定跨度。单选标签显示为文字,多选标签使用轻量徽标。长内容自动换行;弹窗最高为视口高度的 85%,超出后正文滚动,标题保持可见。
|
|
1544
|
+
|
|
1545
|
+
`AutoCrudTable` 的 `form.labelAlign` 和 `form.labelWidth` 同时作用于创建、编辑及详情弹窗。例如 `form={{ columns: 1, labelAlign: 'left', labelWidth: 100 }}` 表示单列、左侧标签文字左对齐,标签宽度为 100px。`top` 表示上下布局(默认),`right` 表示左侧标签文字右对齐;`labelWidth` 仅在 `left` / `right` 布局时生效。
|
|
1546
|
+
|
|
1533
1547
|
### 使用 useDataTable Hook
|
|
1534
1548
|
|
|
1535
1549
|
```typescript
|
package/dist/index.cjs
CHANGED
|
@@ -25,6 +25,8 @@ let __wordrhyme_formily_shadcn = require("@wordrhyme/formily-shadcn");
|
|
|
25
25
|
__wordrhyme_formily_shadcn = require_position.__toESM(__wordrhyme_formily_shadcn);
|
|
26
26
|
let __formily_core = require("@formily/core");
|
|
27
27
|
__formily_core = require_position.__toESM(__formily_core);
|
|
28
|
+
let __formily_react = require("@formily/react");
|
|
29
|
+
__formily_react = require_position.__toESM(__formily_react);
|
|
28
30
|
let __formily_reactive = require("@formily/reactive");
|
|
29
31
|
__formily_reactive = require_position.__toESM(__formily_reactive);
|
|
30
32
|
let sonner = require("sonner");
|
|
@@ -5478,6 +5480,7 @@ function FormModal({ open, onOpenChange, title, description, children, variant =
|
|
|
5478
5480
|
open,
|
|
5479
5481
|
onOpenChange,
|
|
5480
5482
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.SheetContent, {
|
|
5483
|
+
...!description ? { "aria-describedby": void 0 } : {},
|
|
5481
5484
|
side,
|
|
5482
5485
|
className: cn("sm:max-w-lg flex flex-col p-0", className),
|
|
5483
5486
|
children: [
|
|
@@ -5503,6 +5506,7 @@ function FormModal({ open, onOpenChange, title, description, children, variant =
|
|
|
5503
5506
|
open,
|
|
5504
5507
|
onOpenChange,
|
|
5505
5508
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.DialogContent, {
|
|
5509
|
+
...!description ? { "aria-describedby": void 0 } : {},
|
|
5506
5510
|
className: cn("max-w-2xl sm:max-w-2xl flex flex-col max-h-[85vh] overflow-hidden p-0", className),
|
|
5507
5511
|
children: [
|
|
5508
5512
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.DialogHeader, {
|
|
@@ -5624,6 +5628,8 @@ function createFormSchema(schema, options) {
|
|
|
5624
5628
|
const inferredByName = inferComponentByFieldName(key);
|
|
5625
5629
|
const component = inferredByName?.component ?? fieldTypeToFormilyComponent[parsed.type];
|
|
5626
5630
|
const inferredProps = inferredByName?.props ?? {};
|
|
5631
|
+
const componentProps = getComponentProps(parsed.type, parsed);
|
|
5632
|
+
if (parsed.type === "enum" && override?.enum) componentProps.options = override.enum;
|
|
5627
5633
|
properties[key] = {
|
|
5628
5634
|
type: mapToJsonSchemaType(parsed.type),
|
|
5629
5635
|
title: humanize$1(key),
|
|
@@ -5632,7 +5638,7 @@ function createFormSchema(schema, options) {
|
|
|
5632
5638
|
"x-decorator-props": decoratorProps,
|
|
5633
5639
|
"x-component": component,
|
|
5634
5640
|
"x-component-props": {
|
|
5635
|
-
...
|
|
5641
|
+
...componentProps,
|
|
5636
5642
|
...inferredProps
|
|
5637
5643
|
},
|
|
5638
5644
|
...parsed.enumValues && { enum: parsed.enumValues.map((v) => ({
|
|
@@ -5666,6 +5672,51 @@ function createEditFormSchema(schema, options) {
|
|
|
5666
5672
|
});
|
|
5667
5673
|
}
|
|
5668
5674
|
|
|
5675
|
+
//#endregion
|
|
5676
|
+
//#region src/components/auto-crud/read-pretty-field.tsx
|
|
5677
|
+
const ReadPrettyBooleanLocale = (0, react.createContext)(zhCN.boolean);
|
|
5678
|
+
const ReadPrettyRenderers = (0, react.createContext)({});
|
|
5679
|
+
function ReadPrettyField({ options }) {
|
|
5680
|
+
const field = (0, __formily_react.useField)();
|
|
5681
|
+
const schema = (0, __formily_react.useFieldSchema)();
|
|
5682
|
+
const renderCustomValue = (0, react.useContext)(ReadPrettyRenderers)[field.path.toString()];
|
|
5683
|
+
return renderCustomValue ? renderCustomValue() : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReadPrettyValue, {
|
|
5684
|
+
value: field.value,
|
|
5685
|
+
options: options?.length ? options : field.dataSource,
|
|
5686
|
+
date: schema["x-component"] === "DatePicker"
|
|
5687
|
+
});
|
|
5688
|
+
}
|
|
5689
|
+
function ReadPrettyValue({ value, options: choices, date }) {
|
|
5690
|
+
const booleanLocale = (0, react.useContext)(ReadPrettyBooleanLocale);
|
|
5691
|
+
useDateFormatterVersion();
|
|
5692
|
+
const renderValue = (item) => {
|
|
5693
|
+
if (item == null || item === "") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5694
|
+
className: "text-muted-foreground",
|
|
5695
|
+
children: "-"
|
|
5696
|
+
});
|
|
5697
|
+
const option = choices?.find((choice) => String(choice.value) === String(item));
|
|
5698
|
+
if (option) return Array.isArray(value) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
|
|
5699
|
+
variant: "secondary",
|
|
5700
|
+
className: "font-normal",
|
|
5701
|
+
children: option.label
|
|
5702
|
+
}) : option.label;
|
|
5703
|
+
if (typeof item === "boolean") return item ? booleanLocale.true : booleanLocale.false;
|
|
5704
|
+
if (item instanceof Date || date) return formatDate(item);
|
|
5705
|
+
if (typeof item === "object") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
5706
|
+
className: "rounded-md bg-muted/50 p-3 text-sm whitespace-pre-wrap break-words",
|
|
5707
|
+
children: JSON.stringify(item, null, 2)
|
|
5708
|
+
});
|
|
5709
|
+
return String(item);
|
|
5710
|
+
};
|
|
5711
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5712
|
+
className: "min-w-0 whitespace-pre-wrap break-words text-base leading-6 text-foreground",
|
|
5713
|
+
children: Array.isArray(value) ? value.length ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5714
|
+
className: "flex flex-wrap gap-2",
|
|
5715
|
+
children: value.map((item, index$1) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: renderValue(item) }, index$1))
|
|
5716
|
+
}) : renderValue(null) : renderValue(value)
|
|
5717
|
+
});
|
|
5718
|
+
}
|
|
5719
|
+
|
|
5669
5720
|
//#endregion
|
|
5670
5721
|
//#region src/lib/crud-reference-projection.ts
|
|
5671
5722
|
function isRecord$1(value) {
|
|
@@ -5814,12 +5865,8 @@ function normalizeFieldOptions$1(options) {
|
|
|
5814
5865
|
* 从统一字段配置生成 Formily overrides。
|
|
5815
5866
|
* `legacyOverrides` 保持兼容旧 API,字段级 `form` 配置优先级最高。
|
|
5816
5867
|
*/
|
|
5817
|
-
function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
5868
|
+
function buildFormOverrides(fields, legacyOverrides, denyFields, mode = "edit") {
|
|
5818
5869
|
const result = { ...legacyOverrides };
|
|
5819
|
-
if (denyFields) for (const field of denyFields) result[field] = {
|
|
5820
|
-
...result[field],
|
|
5821
|
-
"x-hidden": true
|
|
5822
|
-
};
|
|
5823
5870
|
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
5824
5871
|
const fieldOptions = normalizeFieldOptions$1((config.form && typeof config.form === "object" ? config.form : void 0)?.enum) ?? normalizeFieldOptions$1(config.enum);
|
|
5825
5872
|
const fieldDataSource = fieldOptions || !config.dataSource ? void 0 : normalizeDataSourceConfig(config.dataSource);
|
|
@@ -5827,10 +5874,6 @@ function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
|
5827
5874
|
...result[key],
|
|
5828
5875
|
title: config.label
|
|
5829
5876
|
};
|
|
5830
|
-
if (config.hidden) result[key] = {
|
|
5831
|
-
...result[key],
|
|
5832
|
-
"x-hidden": true
|
|
5833
|
-
};
|
|
5834
5877
|
if (fieldOptions) result[key] = {
|
|
5835
5878
|
...result[key],
|
|
5836
5879
|
enum: fieldOptions
|
|
@@ -5839,15 +5882,27 @@ function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
|
5839
5882
|
...result[key],
|
|
5840
5883
|
"x-data-source": config.dataSource
|
|
5841
5884
|
};
|
|
5842
|
-
if (config.form === false) result[key] = {
|
|
5885
|
+
if (config.form === false && mode !== "view") result[key] = {
|
|
5843
5886
|
...result[key],
|
|
5844
5887
|
"x-hidden": true
|
|
5845
5888
|
};
|
|
5846
|
-
else if (config.form && typeof config.form === "object")
|
|
5889
|
+
else if (config.form && typeof config.form === "object") {
|
|
5890
|
+
const { "x-hidden": formHidden,...sharedFormConfig } = config.form;
|
|
5891
|
+
result[key] = {
|
|
5892
|
+
...result[key],
|
|
5893
|
+
...sharedFormConfig,
|
|
5894
|
+
...mode !== "view" && formHidden !== void 0 ? { "x-hidden": formHidden } : {}
|
|
5895
|
+
};
|
|
5896
|
+
}
|
|
5897
|
+
if (config.hidden) result[key] = {
|
|
5847
5898
|
...result[key],
|
|
5848
|
-
|
|
5899
|
+
"x-hidden": true
|
|
5849
5900
|
};
|
|
5850
5901
|
}
|
|
5902
|
+
for (const field of denyFields ?? []) result[field] = {
|
|
5903
|
+
...result[field],
|
|
5904
|
+
"x-hidden": true
|
|
5905
|
+
};
|
|
5851
5906
|
return result;
|
|
5852
5907
|
}
|
|
5853
5908
|
|
|
@@ -5910,6 +5965,13 @@ const defaultFieldComponents = {
|
|
|
5910
5965
|
decorator: "FormItem"
|
|
5911
5966
|
}
|
|
5912
5967
|
};
|
|
5968
|
+
const readPrettyFieldComponents = Object.fromEntries(Object.entries({
|
|
5969
|
+
...__wordrhyme_formily_shadcn.defaultComponentRegistry,
|
|
5970
|
+
...defaultFieldComponents
|
|
5971
|
+
}).filter(([, config]) => "decorator" in config).map(([name, config]) => [name, {
|
|
5972
|
+
...config,
|
|
5973
|
+
component: (0, __wordrhyme_formily_shadcn.connect)(config.component, (0, __formily_react.mapReadPretty)(ReadPrettyField))
|
|
5974
|
+
}]));
|
|
5913
5975
|
const AUTO_CRUD_DATA_SOURCE_SCOPE_KEY = "$autoCrudDataSource";
|
|
5914
5976
|
const POPUP_SCROLL_LOAD_THRESHOLD$1 = 24;
|
|
5915
5977
|
const dataSourceReactionStates = /* @__PURE__ */ new WeakMap();
|
|
@@ -5938,7 +6000,8 @@ function mergeReactions(existing, reaction) {
|
|
|
5938
6000
|
if (Array.isArray(existing)) return existing.includes(reaction) ? existing : [...existing, reaction];
|
|
5939
6001
|
return [existing, reaction];
|
|
5940
6002
|
}
|
|
5941
|
-
function applyDataSourceReactions(schema) {
|
|
6003
|
+
function applyDataSourceReactions(schema, readPretty = false) {
|
|
6004
|
+
if (readPretty) schema["x-pattern"] = "readPretty";
|
|
5942
6005
|
const dataSourceConfig = getSchemaDataSourceConfig(schema);
|
|
5943
6006
|
if (dataSourceConfig) {
|
|
5944
6007
|
const reaction = `{{${AUTO_CRUD_DATA_SOURCE_SCOPE_KEY}(${JSON.stringify(dataSourceConfig)})}}`;
|
|
@@ -5946,12 +6009,12 @@ function applyDataSourceReactions(schema) {
|
|
|
5946
6009
|
}
|
|
5947
6010
|
const properties = schema.properties;
|
|
5948
6011
|
if (properties && typeof properties === "object" && !Array.isArray(properties)) {
|
|
5949
|
-
for (const property of Object.values(properties)) if (property && typeof property === "object" && !Array.isArray(property)) applyDataSourceReactions(property);
|
|
6012
|
+
for (const property of Object.values(properties)) if (property && typeof property === "object" && !Array.isArray(property)) applyDataSourceReactions(property, readPretty);
|
|
5950
6013
|
}
|
|
5951
6014
|
const items = schema.items;
|
|
5952
6015
|
if (Array.isArray(items)) {
|
|
5953
|
-
for (const item of items) if (item && typeof item === "object") applyDataSourceReactions(item);
|
|
5954
|
-
} else if (items && typeof items === "object") applyDataSourceReactions(items);
|
|
6016
|
+
for (const item of items) if (item && typeof item === "object") applyDataSourceReactions(item, readPretty);
|
|
6017
|
+
} else if (items && typeof items === "object") applyDataSourceReactions(items, readPretty);
|
|
5955
6018
|
}
|
|
5956
6019
|
function getDataSourceReactionState(field) {
|
|
5957
6020
|
const existing = dataSourceReactionStates.get(field);
|
|
@@ -5996,7 +6059,7 @@ function loadAutoCrudDataSource({ entry, field, registryVersion, search, sourceK
|
|
|
5996
6059
|
});
|
|
5997
6060
|
setAutoCrudDataSourceOptions(field, state.options);
|
|
5998
6061
|
if (!append && state.loadKey === loadKey && state.registryVersion === registryVersion) return;
|
|
5999
|
-
if (entry.reset && state.dependencyKey !== void 0 && state.dependencyKey !== dependencyKey) field.setValue(void 0);
|
|
6062
|
+
if (entry.reset && !field.readPretty && state.dependencyKey !== void 0 && state.dependencyKey !== dependencyKey) field.setValue(void 0);
|
|
6000
6063
|
state.dependencyKey = dependencyKey;
|
|
6001
6064
|
if (!append) {
|
|
6002
6065
|
state.loadKey = loadKey;
|
|
@@ -6172,7 +6235,10 @@ function createAutoCrudDataSourceReaction(config, registryState) {
|
|
|
6172
6235
|
};
|
|
6173
6236
|
}
|
|
6174
6237
|
function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, fields, overrides, scope: scopeProp, mode = "create", loading = false, gridColumns = 1, labelAlign = "top", labelWidth, showSubmitButton = true }, ref) {
|
|
6175
|
-
const form = (0, react.useMemo)(() => (0, __formily_core.createForm)({
|
|
6238
|
+
const form = (0, react.useMemo)(() => (0, __formily_core.createForm)({
|
|
6239
|
+
initialValues,
|
|
6240
|
+
pattern: mode === "view" ? "readPretty" : "editable"
|
|
6241
|
+
}), [JSON.stringify(initialValues), mode]);
|
|
6176
6242
|
const dataSourceRegistryState = (0, react.useMemo)(() => (0, __formily_reactive.observable)({ version: 0 }), []);
|
|
6177
6243
|
const updateDataSourceRegistryState = (0, react.useCallback)(() => {
|
|
6178
6244
|
(0, __formily_reactive.action)(() => {
|
|
@@ -6180,40 +6246,75 @@ function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, fields, ove
|
|
|
6180
6246
|
});
|
|
6181
6247
|
}, [dataSourceRegistryState]);
|
|
6182
6248
|
const dataSourceRegistryVersion = useRegistryVersion$1(dataSources.subscribe, updateDataSourceRegistryState);
|
|
6183
|
-
const formOverrides = (0, react.useMemo)(() => buildFormOverrides(fields, overrides
|
|
6249
|
+
const formOverrides = (0, react.useMemo)(() => buildFormOverrides(fields, overrides, void 0, mode), [
|
|
6250
|
+
fields,
|
|
6251
|
+
overrides,
|
|
6252
|
+
mode
|
|
6253
|
+
]);
|
|
6184
6254
|
const formSchema = (0, react.useMemo)(() => {
|
|
6185
|
-
const nextSchema = createEditFormSchema(zodSchema, {
|
|
6255
|
+
const nextSchema = (mode === "view" ? createFormSchema : createEditFormSchema)(zodSchema, {
|
|
6186
6256
|
overrides: formOverrides,
|
|
6187
6257
|
layout: "grid",
|
|
6188
6258
|
gridColumns
|
|
6189
6259
|
});
|
|
6190
|
-
|
|
6260
|
+
const grid = typeof nextSchema.properties === "object" ? nextSchema.properties.layout : void 0;
|
|
6261
|
+
if (mode === "view" && grid && typeof grid === "object") {
|
|
6262
|
+
grid["x-component-props"] = {
|
|
6263
|
+
...grid["x-component-props"],
|
|
6264
|
+
className: (0, __wordrhyme_shadcn.cn)(grid["x-component-props"]?.className, "gap-x-10 gap-y-7 py-2")
|
|
6265
|
+
};
|
|
6266
|
+
const properties = typeof grid.properties === "object" ? grid.properties : {};
|
|
6267
|
+
for (const property of Object.values(properties)) {
|
|
6268
|
+
const decoratorProps = property["x-decorator-props"];
|
|
6269
|
+
const fullWidth = property.type === "object" || property.type === "array" || ["Textarea", "RichTextEditor"].includes(property["x-component"]);
|
|
6270
|
+
property["x-decorator-props"] = {
|
|
6271
|
+
colon: false,
|
|
6272
|
+
...decoratorProps,
|
|
6273
|
+
className: (0, __wordrhyme_shadcn.cn)(fullWidth && decoratorProps?.gridSpan == null && "col-span-full", decoratorProps?.className)
|
|
6274
|
+
};
|
|
6275
|
+
}
|
|
6276
|
+
}
|
|
6277
|
+
applyDataSourceReactions(nextSchema, mode === "view");
|
|
6191
6278
|
return nextSchema;
|
|
6192
6279
|
}, [
|
|
6193
6280
|
zodSchema,
|
|
6194
6281
|
formOverrides,
|
|
6195
6282
|
gridColumns,
|
|
6196
|
-
dataSourceRegistryVersion
|
|
6283
|
+
dataSourceRegistryVersion,
|
|
6284
|
+
mode
|
|
6197
6285
|
]);
|
|
6198
6286
|
const formLayout = (0, react.useMemo)(() => {
|
|
6199
6287
|
const inlineLabel = labelAlign === "left" || labelAlign === "right";
|
|
6200
|
-
return {
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6288
|
+
return { itemProps: {
|
|
6289
|
+
container: mode === "view" ? { className: "min-w-0 space-y-0 gap-2" } : void 0,
|
|
6290
|
+
label: {
|
|
6291
|
+
placement: inlineLabel ? "start" : "top",
|
|
6292
|
+
className: (0, __wordrhyme_shadcn.cn)(mode === "view" && "mb-0 text-sm font-normal text-muted-foreground leading-5", labelAlign === "right" && "text-right"),
|
|
6293
|
+
style: inlineLabel && labelWidth != null ? { width: labelWidth } : void 0
|
|
6294
|
+
}
|
|
6295
|
+
} };
|
|
6296
|
+
}, [
|
|
6297
|
+
labelAlign,
|
|
6298
|
+
labelWidth,
|
|
6299
|
+
mode
|
|
6300
|
+
]);
|
|
6208
6301
|
const fieldComponents = (0, react.useMemo)(() => ({ fields: {
|
|
6209
6302
|
...defaultFieldComponents,
|
|
6303
|
+
...mode === "view" ? {
|
|
6304
|
+
...readPrettyFieldComponents,
|
|
6305
|
+
ObjectField: {
|
|
6306
|
+
component: ReadPrettyField,
|
|
6307
|
+
decorator: "FormItem"
|
|
6308
|
+
}
|
|
6309
|
+
} : {},
|
|
6210
6310
|
...components.all()
|
|
6211
|
-
} }), [useRegistryVersion$1(components.subscribe)]);
|
|
6311
|
+
} }), [useRegistryVersion$1(components.subscribe), mode]);
|
|
6212
6312
|
const scope = (0, react.useMemo)(() => ({
|
|
6213
6313
|
...scopeProp,
|
|
6214
6314
|
[AUTO_CRUD_DATA_SOURCE_SCOPE_KEY]: (config) => createAutoCrudDataSourceReaction(config, dataSourceRegistryState)
|
|
6215
6315
|
}), [dataSourceRegistryState, scopeProp]);
|
|
6216
6316
|
const handleSubmit = async () => {
|
|
6317
|
+
if (mode === "view" || !onSubmit) return;
|
|
6217
6318
|
await form.validate();
|
|
6218
6319
|
if (form.valid) await onSubmit(form.values);
|
|
6219
6320
|
};
|
|
@@ -6225,7 +6326,7 @@ function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, fields, ove
|
|
|
6225
6326
|
schema: formSchema,
|
|
6226
6327
|
components: fieldComponents,
|
|
6227
6328
|
scope
|
|
6228
|
-
}), showSubmitButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6329
|
+
}), mode !== "view" && showSubmitButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6229
6330
|
className: "flex justify-end gap-2 mt-6",
|
|
6230
6331
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Button, {
|
|
6231
6332
|
type: "button",
|
|
@@ -6241,7 +6342,7 @@ const AutoForm = (0, react.forwardRef)(AutoFormInner);
|
|
|
6241
6342
|
//#endregion
|
|
6242
6343
|
//#region src/components/auto-crud/crud-form-modal.tsx
|
|
6243
6344
|
function CrudFormModal({ open, onOpenChange, mode, schema, initialValues, onSubmit, loading = false, variant = "dialog", overrides, scope, title, locale = zhCN.formModal, gridColumns, labelAlign, labelWidth, className }) {
|
|
6244
|
-
const defaultTitle = mode === "create" ? locale.createTitle : locale.editTitle;
|
|
6345
|
+
const defaultTitle = mode === "create" ? locale.createTitle : mode === "edit" ? locale.editTitle : zhCN.viewModal.title;
|
|
6245
6346
|
const formRef = (0, react.useRef)(null);
|
|
6246
6347
|
const handleSubmit = async () => {
|
|
6247
6348
|
await formRef.current?.submit();
|
|
@@ -6252,7 +6353,7 @@ function CrudFormModal({ open, onOpenChange, mode, schema, initialValues, onSubm
|
|
|
6252
6353
|
title: title ?? defaultTitle,
|
|
6253
6354
|
variant,
|
|
6254
6355
|
className,
|
|
6255
|
-
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6356
|
+
footer: mode !== "view" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6256
6357
|
className: "flex justify-end gap-2",
|
|
6257
6358
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Button, {
|
|
6258
6359
|
type: "button",
|
|
@@ -6265,14 +6366,16 @@ function CrudFormModal({ open, onOpenChange, mode, schema, initialValues, onSubm
|
|
|
6265
6366
|
disabled: loading,
|
|
6266
6367
|
children: loading ? locale.submitting : mode === "create" ? locale.create : locale.save
|
|
6267
6368
|
})]
|
|
6268
|
-
}),
|
|
6369
|
+
}) : void 0,
|
|
6269
6370
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoForm, {
|
|
6270
6371
|
ref: formRef,
|
|
6271
6372
|
schema,
|
|
6272
|
-
mode
|
|
6373
|
+
...mode === "view" ? { mode } : {
|
|
6374
|
+
mode,
|
|
6375
|
+
onSubmit
|
|
6376
|
+
},
|
|
6273
6377
|
initialValues,
|
|
6274
6378
|
loading,
|
|
6275
|
-
onSubmit,
|
|
6276
6379
|
overrides,
|
|
6277
6380
|
scope,
|
|
6278
6381
|
gridColumns,
|
|
@@ -7652,7 +7755,7 @@ function ViewModal(props) {
|
|
|
7652
7755
|
if (!props.open || !props.data) return null;
|
|
7653
7756
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ViewModalContent, { ...props });
|
|
7654
7757
|
}
|
|
7655
|
-
function ViewModalContent({ open, onOpenChange, variant, data, schema, fields: fieldConfig, dynamicOptions, denyFields, locale, tableOverrides, view }) {
|
|
7758
|
+
function ViewModalContent({ open, onOpenChange, variant, data, schema, fields: fieldConfig, dynamicOptions, denyFields, locale, tableOverrides, view, form }) {
|
|
7656
7759
|
const excluded = react.useMemo(() => {
|
|
7657
7760
|
const denied = new Set(denyFields ?? []);
|
|
7658
7761
|
return Object.keys(schema.shape).filter((key) => {
|
|
@@ -7667,70 +7770,82 @@ function ViewModalContent({ open, onOpenChange, variant, data, schema, fields: f
|
|
|
7667
7770
|
]);
|
|
7668
7771
|
const rows = react.useMemo(() => data ? [data] : [], [data]);
|
|
7669
7772
|
const resolvedOptions = useDynamicResolveOptions(fieldConfig, rows, excluded);
|
|
7670
|
-
const
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
|
|
7674
|
-
|
|
7675
|
-
const
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
|
-
|
|
7688
|
-
|
|
7689
|
-
|
|
7690
|
-
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", {
|
|
7714
|
-
className: "text-sm font-medium text-muted-foreground",
|
|
7715
|
-
children: cell.column.columnDef.meta?.label ?? humanize(cell.column.id)
|
|
7716
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
7717
|
-
className: "col-span-2 min-w-0 whitespace-pre-wrap break-words text-sm",
|
|
7718
|
-
children: (0, __tanstack_react_table.flexRender)(cell.column.columnDef.cell, cell.getContext())
|
|
7719
|
-
})]
|
|
7720
|
-
}, cell.id))
|
|
7721
|
-
});
|
|
7722
|
-
if (variant === "sheet") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.Sheet, {
|
|
7723
|
-
open,
|
|
7724
|
-
onOpenChange,
|
|
7725
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.SheetContent, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.SheetHeader, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.SheetTitle, { children: locale.viewModal.title }) }), content] })
|
|
7773
|
+
const table = (0, __tanstack_react_table.useReactTable)({
|
|
7774
|
+
data: rows,
|
|
7775
|
+
columns: react.useMemo(() => {
|
|
7776
|
+
const overrides$1 = {};
|
|
7777
|
+
for (const [key, fieldSchema] of Object.entries(schema.shape).filter(([fieldKey]) => !excluded.includes(fieldKey))) {
|
|
7778
|
+
const config = fieldConfig?.[key] ?? {};
|
|
7779
|
+
const tableConfig = getTableConfig(config);
|
|
7780
|
+
const listOverride = tableOverrides?.[key];
|
|
7781
|
+
const options = getTableOptions(config) ?? resolvedOptions.optionsByField[key] ?? (tableConfig?.dataSource !== void 0 ? void 0 : dynamicOptions?.[key]);
|
|
7782
|
+
overrides$1[key] = {
|
|
7783
|
+
label: tableConfig?.label ?? config.label ?? listOverride?.label ?? humanize(key),
|
|
7784
|
+
index: tableConfig?.index ?? listOverride?.index,
|
|
7785
|
+
cell: ({ getValue, row }) => {
|
|
7786
|
+
const value = getValue();
|
|
7787
|
+
return config.format?.(value, {
|
|
7788
|
+
row: row.original,
|
|
7789
|
+
target: "display"
|
|
7790
|
+
}) ?? (tableConfig?.display && tableConfig.display !== "auto" || options?.some((option) => option.badgeTone) ? renderFieldValue(value, parseZodField(fieldSchema).type, locale.boolean, options, tableConfig?.display ?? "auto", Infinity) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReadPrettyValue, {
|
|
7791
|
+
value,
|
|
7792
|
+
options,
|
|
7793
|
+
date: parseZodField(fieldSchema).type === "date"
|
|
7794
|
+
}));
|
|
7795
|
+
},
|
|
7796
|
+
...view?.presentation === "table" ? listOverride : void 0,
|
|
7797
|
+
hidden: false,
|
|
7798
|
+
...view?.overrides?.[key]
|
|
7799
|
+
};
|
|
7800
|
+
}
|
|
7801
|
+
return createTableSchema(schema, {
|
|
7802
|
+
overrides: overrides$1,
|
|
7803
|
+
exclude: excluded
|
|
7804
|
+
});
|
|
7805
|
+
}, [
|
|
7806
|
+
schema,
|
|
7807
|
+
excluded,
|
|
7808
|
+
fieldConfig,
|
|
7809
|
+
tableOverrides,
|
|
7810
|
+
view,
|
|
7811
|
+
resolvedOptions.optionsByField,
|
|
7812
|
+
dynamicOptions,
|
|
7813
|
+
locale.boolean
|
|
7814
|
+
]),
|
|
7815
|
+
getCoreRowModel: (0, __tanstack_react_table.getCoreRowModel)()
|
|
7726
7816
|
});
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
|
|
7817
|
+
const detailSchema = react.useMemo(() => schema.omit(Object.fromEntries(excluded.map((key) => [key, true]))), [schema, excluded]);
|
|
7818
|
+
const overrides = buildFormOverrides(fieldConfig, form?.overrides, denyFields, "view");
|
|
7819
|
+
const renderers = {};
|
|
7820
|
+
for (const [index$1, cell] of (table.getRowModel().rows[0]?.getAllCells() ?? []).entries()) {
|
|
7821
|
+
const key = cell.column.id;
|
|
7822
|
+
overrides[key] = {
|
|
7823
|
+
...overrides[key],
|
|
7824
|
+
title: cell.column.columnDef.meta?.label ?? humanize(key),
|
|
7825
|
+
"x-index": index$1
|
|
7826
|
+
};
|
|
7827
|
+
renderers[key] = () => (0, __tanstack_react_table.flexRender)(cell.column.columnDef.cell, cell.getContext());
|
|
7828
|
+
delete overrides[key]["x-data-source"];
|
|
7829
|
+
}
|
|
7830
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReadPrettyBooleanLocale.Provider, {
|
|
7831
|
+
value: locale.boolean,
|
|
7832
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReadPrettyRenderers.Provider, {
|
|
7833
|
+
value: renderers,
|
|
7834
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CrudFormModal, {
|
|
7835
|
+
open,
|
|
7836
|
+
onOpenChange,
|
|
7837
|
+
mode: "view",
|
|
7838
|
+
variant,
|
|
7839
|
+
schema: detailSchema,
|
|
7840
|
+
initialValues: data ?? void 0,
|
|
7841
|
+
overrides,
|
|
7842
|
+
scope: form?.scope,
|
|
7843
|
+
title: locale.viewModal.title,
|
|
7844
|
+
gridColumns: form?.columns,
|
|
7845
|
+
labelAlign: form?.labelAlign,
|
|
7846
|
+
labelWidth: form?.labelWidth,
|
|
7847
|
+
className: form?.className
|
|
7848
|
+
})
|
|
7734
7849
|
})
|
|
7735
7850
|
});
|
|
7736
7851
|
}
|
|
@@ -8235,6 +8350,8 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
8235
8350
|
scope: formConfig?.scope,
|
|
8236
8351
|
locale: locale.formModal,
|
|
8237
8352
|
gridColumns: formConfig?.columns,
|
|
8353
|
+
labelAlign: formConfig?.labelAlign,
|
|
8354
|
+
labelWidth: formConfig?.labelWidth,
|
|
8238
8355
|
className: formConfig?.className
|
|
8239
8356
|
}),
|
|
8240
8357
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ViewModal, {
|
|
@@ -8248,7 +8365,8 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
|
|
|
8248
8365
|
denyFields,
|
|
8249
8366
|
locale,
|
|
8250
8367
|
tableOverrides: detailTableOverrides,
|
|
8251
|
-
view: viewConfig
|
|
8368
|
+
view: viewConfig,
|
|
8369
|
+
form: formConfig
|
|
8252
8370
|
}),
|
|
8253
8371
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.AlertDialog, {
|
|
8254
8372
|
open: resource.modal.deleteOpen,
|