@wordrhyme/auto-crud 1.3.5 → 1.3.8

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
@@ -268,7 +268,7 @@ interface AutoCrudTableProps<TSchema> {
268
268
  batchFields?: (string | BatchUpdateField)[]; // 批量更新字段
269
269
  /** @deprecated 新代码请使用 actions.batch */
270
270
  batchActions?: BatchActionConfig<z.output<TSchema>>;
271
- defaultSort?: any[]; // 默认排序
271
+ defaultSort?: any[]; // 手动 resource 的 UI 默认排序;useAutoCrudResource 请配置 options.defaultSort
272
272
  };
273
273
  form?: {
274
274
  overrides?: Record<string, any>; // 表单覆盖配置
@@ -280,11 +280,13 @@ interface AutoCrudTableProps<TSchema> {
280
280
  * 旧写法 actions={[...]} 仍表示行操作;
281
281
  * 新写法 actions={{ toolbar, row, batch }} 可集中配置三类操作。
282
282
  */
283
- actions?: RowActionConfig<z.output<TSchema>> | {
284
- toolbar?: ToolbarActionConfig;
285
- row?: RowActionConfig<z.output<TSchema>>;
286
- batch?: BatchActionConfig<z.output<TSchema>>;
287
- };
283
+ actions?:
284
+ | RowActionConfig<z.output<TSchema>>
285
+ | {
286
+ toolbar?: ToolbarActionConfig;
287
+ row?: RowActionConfig<z.output<TSchema>>;
288
+ batch?: BatchActionConfig<z.output<TSchema>>;
289
+ };
288
290
  /** @deprecated 新代码请使用 actions.toolbar */
289
291
  toolbar?: ToolbarActionConfig;
290
292
  /** @deprecated 新代码请使用 actions.toolbar */
@@ -302,6 +304,11 @@ interface AutoCrudTableProps<TSchema> {
302
304
  interface UseAutoCrudResourceConfig<TData> {
303
305
  dataSource: DataSource<TData>; // 数据源
304
306
  schema: z.ZodType<TData>; // Zod Schema
307
+ options?: {
308
+ defaultSort?: Array<{ id: string; desc: boolean }> | false;
309
+ // undefined: schema 有 createdAt 时默认 createdAt desc
310
+ // false: 不应用默认排序
311
+ };
305
312
  }
306
313
  ```
307
314
 
@@ -776,7 +783,12 @@ crudActions.register({
776
783
  actions={{
777
784
  row: [
778
785
  { type: 'custom', label: '分配', onClick: (row) => assign(row.id) },
779
- { type: 'custom', label: '预览', onClick: (row) => preview(row), position: 'start' },
786
+ {
787
+ type: 'custom',
788
+ label: '预览',
789
+ onClick: (row) => preview(row),
790
+ position: 'start',
791
+ },
780
792
  ],
781
793
  }}
782
794
  />
@@ -849,7 +861,9 @@ type RowCustomActionItem<T> = ActionMeta & {
849
861
  type: 'custom';
850
862
  label?: string;
851
863
  onClick?: (row: T) => void;
852
- component?: React.ReactNode | ((context: AutoCrudRowActionContext<T>) => React.ReactNode);
864
+ component?:
865
+ | React.ReactNode
866
+ | ((context: AutoCrudRowActionContext<T>) => React.ReactNode);
853
867
  position?: 'start' | 'end'; // 仅无内置项时生效,默认 end
854
868
  separator?: boolean;
855
869
  variant?: 'default' | 'destructive';
@@ -992,7 +1006,7 @@ import {
992
1006
  createSelectColumn, // 创建选择列
993
1007
  createActionsColumn, // 创建操作列
994
1008
  createFormSchema, // Zod Schema → Formily Schema
995
- createEditFormSchema, // 创建编辑表单 Schema(排除 id, createdAt, updatedAt)
1009
+ createEditFormSchema, // 创建编辑表单 Schema(排除平台托管字段)
996
1010
  } from '@wordrhyme/auto-crud';
997
1011
  ```
998
1012
 
@@ -1254,7 +1268,15 @@ function CustomCrudPage() {
1254
1268
  });
1255
1269
 
1256
1270
  const formSchema = createFormSchema(taskSchema, {
1257
- exclude: ["id", "createdAt", "updatedAt"],
1271
+ exclude: [
1272
+ "id",
1273
+ "createdAt",
1274
+ "updatedAt",
1275
+ "createdBy",
1276
+ "createdByType",
1277
+ "updatedBy",
1278
+ "updatedByType",
1279
+ ],
1258
1280
  });
1259
1281
 
1260
1282
  return (
package/dist/index.cjs CHANGED
@@ -2062,6 +2062,12 @@ function DataTableSortList({ table, disabled,...props }) {
2062
2062
  window.addEventListener("keydown", onKeyDown);
2063
2063
  return () => window.removeEventListener("keydown", onKeyDown);
2064
2064
  }, []);
2065
+ const onTriggerKeyDown = react.useCallback((event) => {
2066
+ if (REMOVE_SORT_SHORTCUTS.includes(event.key.toLowerCase()) && sorting.length > 0) {
2067
+ event.preventDefault();
2068
+ onSortingReset();
2069
+ }
2070
+ }, [sorting.length, onSortingReset]);
2065
2071
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn_ui.Sortable, {
2066
2072
  value: sorting,
2067
2073
  onValueChange: onSortingChange,
@@ -2073,24 +2079,17 @@ function DataTableSortList({ table, disabled,...props }) {
2073
2079
  asChild: true,
2074
2080
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Button, {
2075
2081
  variant: "outline",
2076
- size: "sm",
2077
- className: "font-normal",
2078
- onKeyDown: react.useCallback((event) => {
2079
- if (REMOVE_SORT_SHORTCUTS.includes(event.key.toLowerCase()) && sorting.length > 0) {
2080
- event.preventDefault();
2081
- onSortingReset();
2082
- }
2083
- }, [sorting.length, onSortingReset]),
2082
+ size: "icon-sm",
2083
+ "aria-label": "Sort rows",
2084
+ title: "Sort rows",
2085
+ className: cn(sorting.length > 0 && "w-auto gap-1 px-2"),
2086
+ onKeyDown: onTriggerKeyDown,
2084
2087
  disabled,
2085
- children: [
2086
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ArrowDownUp, { className: "text-muted-foreground" }),
2087
- "Sort",
2088
- sorting.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
2089
- variant: "secondary",
2090
- className: "h-[18.24px] rounded-[3.2px] px-[5.12px] font-mono font-normal text-[10.4px]",
2091
- children: sorting.length
2092
- })
2093
- ]
2088
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ArrowDownUp, { className: "text-muted-foreground" }), sorting.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
2089
+ variant: "secondary",
2090
+ className: "h-[18.24px] rounded-[3.2px] px-[5.12px] font-mono font-normal text-[10.4px]",
2091
+ children: sorting.length
2092
+ })]
2094
2093
  })
2095
2094
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.PopoverContent, {
2096
2095
  "aria-labelledby": labelId,
@@ -2260,14 +2259,15 @@ function DataTableViewOptions({ table, disabled,...props }) {
2260
2259
  const columns = react.useMemo(() => table.getAllColumns().filter((column) => typeof column.accessorFn !== "undefined" && column.getCanHide()), [table]);
2261
2260
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Popover, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.PopoverTrigger, {
2262
2261
  asChild: true,
2263
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Button, {
2262
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Button, {
2264
2263
  "aria-label": "Toggle columns",
2264
+ title: "Toggle columns",
2265
2265
  role: "combobox",
2266
2266
  variant: "outline",
2267
- size: "sm",
2268
- className: "ml-auto flex h-8 font-normal",
2267
+ size: "icon-sm",
2268
+ className: "ml-auto",
2269
2269
  disabled,
2270
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Settings2, { className: "text-muted-foreground" }), "View"]
2270
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Settings2, { className: "text-muted-foreground" })
2271
2271
  })
2272
2272
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.PopoverContent, {
2273
2273
  className: "w-44 p-0",
@@ -3974,7 +3974,7 @@ const filterModeConfig = {
3974
3974
  tooltip: "Linear-style command filters"
3975
3975
  }
3976
3976
  };
3977
- function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode = "simple", search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, deleteConfirmation, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
3977
+ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode, search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, deleteConfirmation, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
3978
3978
  const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
3979
3979
  const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
3980
3980
  const showToggle = modes.length > 1;
@@ -4049,9 +4049,9 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
4049
4049
  asChild: true,
4050
4050
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Button, {
4051
4051
  variant: "outline",
4052
- size: "sm",
4053
- className: "h-8 w-8 p-0",
4052
+ size: "icon-sm",
4054
4053
  "aria-label": `Switch filter mode, current: ${filterModeConfig[currentMode].label}`,
4054
+ title: filterModeConfig[currentMode].tooltip,
4055
4055
  children: (() => {
4056
4056
  const Icon = filterModeConfig[currentMode].icon;
4057
4057
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { className: "size-4 text-muted-foreground" });
@@ -4118,22 +4118,15 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
4118
4118
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4119
4119
  className: "flex min-h-[40px] min-w-0 flex-1 items-start gap-2",
4120
4120
  "data-filter-parent": true,
4121
- children: [
4122
- currentMode !== "simple" && searchInput,
4123
- currentMode !== "simple" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableSortList, {
4124
- table,
4125
- align: "start"
4126
- }),
4127
- filtersContent
4128
- ]
4121
+ children: [currentMode !== "simple" && searchInput, filtersContent]
4129
4122
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4130
4123
  className: "flex items-center gap-2",
4131
4124
  children: [
4132
- currentMode === "simple" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableSortList, {
4125
+ FilterModeSelect,
4126
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableSortList, {
4133
4127
  table,
4134
4128
  align: "end"
4135
4129
  }),
4136
- FilterModeSelect,
4137
4130
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableViewOptions, {
4138
4131
  table,
4139
4132
  align: "end"
@@ -4214,6 +4207,15 @@ function FormModal({ open, onOpenChange, title, description, children, variant =
4214
4207
 
4215
4208
  //#endregion
4216
4209
  //#region src/lib/schema-bridge/zod-to-formily.ts
4210
+ const DEFAULT_FORM_MANAGED_FIELDS = [
4211
+ "id",
4212
+ "createdAt",
4213
+ "updatedAt",
4214
+ "createdBy",
4215
+ "createdByType",
4216
+ "updatedBy",
4217
+ "updatedByType"
4218
+ ];
4217
4219
  /**
4218
4220
  * 将字符串转为人类可读格式
4219
4221
  */
@@ -4296,16 +4298,12 @@ function createFormSchema(schema, options) {
4296
4298
  };
4297
4299
  }
4298
4300
  /**
4299
- * 为编辑模式创建 Form Schema(排除 id, createdAt, updatedAt)
4301
+ * 为编辑模式创建 Form Schema(排除平台托管字段)
4300
4302
  */
4301
4303
  function createEditFormSchema(schema, options) {
4302
4304
  return createFormSchema(schema, {
4303
4305
  ...options,
4304
- exclude: [
4305
- "id",
4306
- "createdAt",
4307
- "updatedAt"
4308
- ]
4306
+ exclude: [...DEFAULT_FORM_MANAGED_FIELDS]
4309
4307
  });
4310
4308
  }
4311
4309
 
@@ -5639,6 +5637,15 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title, local
5639
5637
  });
5640
5638
  }
5641
5639
 
5640
+ //#endregion
5641
+ //#region src/lib/default-sorting.ts
5642
+ function getDefaultSortingForSchema(schema) {
5643
+ return Object.prototype.hasOwnProperty.call(schema.shape, "createdAt") ? [{
5644
+ id: "createdAt",
5645
+ desc: true
5646
+ }] : [];
5647
+ }
5648
+
5642
5649
  //#endregion
5643
5650
  //#region src/lib/crud-actions.ts
5644
5651
  const entries = /* @__PURE__ */ new Map();
@@ -5788,6 +5795,29 @@ const crudActions = {
5788
5795
 
5789
5796
  //#endregion
5790
5797
  //#region src/components/auto-crud/auto-crud-table.tsx
5798
+ const DEFAULT_IMPORT_MANAGED_FIELDS = [
5799
+ "createdAt",
5800
+ "updatedAt",
5801
+ "createdBy",
5802
+ "createdByType",
5803
+ "updatedBy",
5804
+ "updatedByType"
5805
+ ];
5806
+ const DEFAULT_HIDDEN_AUDIT_FIELDS = [
5807
+ "createdBy",
5808
+ "createdByType",
5809
+ "updatedBy",
5810
+ "updatedByType"
5811
+ ];
5812
+ function isDefaultHiddenAuditField(key) {
5813
+ return DEFAULT_HIDDEN_AUDIT_FIELDS.includes(key);
5814
+ }
5815
+ function isFieldTableExplicitlyVisible(config) {
5816
+ return config?.hidden === false || config?.table !== false && typeof config?.table === "object" && config.table.hidden === false;
5817
+ }
5818
+ function isTableOverrideExplicitlyVisible(config) {
5819
+ return config?.hidden === false;
5820
+ }
5791
5821
  let autoCrudToolbarResolver = null;
5792
5822
  function setToolbarResolver(resolver) {
5793
5823
  autoCrudToolbarResolver = resolver;
@@ -6239,10 +6269,18 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState) {
6239
6269
  /**
6240
6270
  * 从统一配置生成隐藏列列表
6241
6271
  */
6242
- function buildHiddenColumns(fields, legacyHidden, denyFields) {
6243
- const hidden = new Set([...legacyHidden ?? [], ...denyFields ?? []]);
6244
- if (fields) {
6245
- for (const [key, config] of Object.entries(fields)) if (config.hidden) hidden.add(key);
6272
+ function buildHiddenColumns(fields, legacyHidden, denyFields, legacyOverrides) {
6273
+ const legacyHiddenSet = new Set(legacyHidden ?? []);
6274
+ const denySet = new Set(denyFields ?? []);
6275
+ const hidden = new Set([
6276
+ ...DEFAULT_HIDDEN_AUDIT_FIELDS,
6277
+ ...legacyHiddenSet,
6278
+ ...denySet
6279
+ ]);
6280
+ for (const key of DEFAULT_HIDDEN_AUDIT_FIELDS) if (!legacyHiddenSet.has(key) && !denySet.has(key) && isTableOverrideExplicitlyVisible(legacyOverrides?.[key])) hidden.delete(key);
6281
+ if (fields) for (const [key, config] of Object.entries(fields)) {
6282
+ if (isDefaultHiddenAuditField(key) && !legacyHiddenSet.has(key) && !denySet.has(key) && isFieldTableExplicitlyVisible(config)) hidden.delete(key);
6283
+ if (config.hidden) hidden.add(key);
6246
6284
  else if (config.table === false) hidden.add(key);
6247
6285
  else if (config.table && typeof config.table === "object" && config.table.hidden) hidden.add(key);
6248
6286
  }
@@ -6346,7 +6384,10 @@ function ViewModal({ open, onOpenChange, variant, data, schema, fields: fieldCon
6346
6384
  className: "grid gap-4 py-4",
6347
6385
  children: Object.entries(shape).filter(([key]) => {
6348
6386
  if (denySet.has(key)) return false;
6349
- return !(fieldConfig?.[key])?.hidden;
6387
+ const config = fieldConfig?.[key];
6388
+ if (config?.hidden) return false;
6389
+ if (isDefaultHiddenAuditField(key) && !isFieldTableExplicitlyVisible(config)) return false;
6390
+ return true;
6350
6391
  }).map(([key, fieldSchema]) => {
6351
6392
  const parsed = parseZodField(fieldSchema);
6352
6393
  const label = fieldConfig?.[key]?.label ?? humanize(key);
@@ -6559,7 +6600,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
6559
6600
  const resolvedToolbarActions = resolveToolbarActionsWithResolver(id, registryToolbarActions, toolbarContext);
6560
6601
  const importColumns = react.useMemo(() => {
6561
6602
  const shape = resolvedSchema.shape;
6562
- const denySet = new Set(denyFields ?? []);
6603
+ const denySet = new Set([...DEFAULT_IMPORT_MANAGED_FIELDS, ...denyFields ?? []]);
6563
6604
  return Object.keys(shape).filter((key) => !denySet.has(key));
6564
6605
  }, [resolvedSchema, denyFields]);
6565
6606
  const handleExport = react.useCallback(async (mode) => {
@@ -6598,15 +6639,21 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
6598
6639
  tableConfig?.overrides,
6599
6640
  dynamicFilterOptions
6600
6641
  ]);
6642
+ const defaultSort = react.useMemo(() => resource.defaultSort ?? tableConfig?.defaultSort ?? getDefaultSortingForSchema(resolvedSchema), [
6643
+ resource.defaultSort,
6644
+ resolvedSchema,
6645
+ tableConfig?.defaultSort
6646
+ ]);
6601
6647
  const formOverrides = react.useMemo(() => buildFormOverrides(resolvedFields, formConfig?.overrides, denyFields), [
6602
6648
  resolvedFields,
6603
6649
  formConfig?.overrides,
6604
6650
  denyFields
6605
6651
  ]);
6606
- const hiddenColumns = react.useMemo(() => buildHiddenColumns(resolvedFields, tableConfig?.hidden, denyFields), [
6652
+ const hiddenColumns = react.useMemo(() => buildHiddenColumns(resolvedFields, tableConfig?.hidden, denyFields, tableConfig?.overrides), [
6607
6653
  resolvedFields,
6608
6654
  tableConfig?.hidden,
6609
- denyFields
6655
+ denyFields,
6656
+ tableConfig?.overrides
6610
6657
  ]);
6611
6658
  const searchConfig = react.useMemo(() => {
6612
6659
  const tableSearch = tableConfig?.search;
@@ -6754,7 +6801,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
6754
6801
  deleteConfirmation: locale.bulkDeleteModal,
6755
6802
  enableExport: canExport,
6756
6803
  showDefaultExport: false,
6757
- initialSorting: tableConfig?.defaultSort,
6804
+ initialSorting: defaultSort,
6758
6805
  onSelectedRowsChange: handleSelectedRowsChange,
6759
6806
  getSelectedRows: getSelectedRowsRef
6760
6807
  }),
@@ -7556,7 +7603,7 @@ function modalReducer(state, action$1) {
7556
7603
  * Hook 主函数
7557
7604
  */
7558
7605
  function useAutoCrudResource({ router, schema, query: queryTransform, options = {} }) {
7559
- const { idKey = "id", defaultVariant = "dialog", hooks, toast: toastAdapter, exportFetcher } = options;
7606
+ const { idKey = "id", defaultVariant = "dialog", hooks, toast: toastAdapter, exportFetcher, defaultSort: defaultSortOption } = options;
7560
7607
  const toast = (0, react.useMemo)(() => toastAdapter === false ? noopToastAdapter : toastAdapter ?? defaultToastAdapter, [toastAdapter]);
7561
7608
  const hooksRef = (0, react.useRef)(hooks);
7562
7609
  (0, react.useEffect)(() => {
@@ -7564,12 +7611,13 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
7564
7611
  }, [hooks]);
7565
7612
  const metadata = (router.meta?.useQuery(void 0, { staleTime: 3e4 }))?.data;
7566
7613
  const resolvedSchema = (0, react.useMemo)(() => mergeMetadataSchema(schema, metadata?.schema), [schema, metadata?.schema]);
7614
+ const defaultSorting = (0, react.useMemo)(() => defaultSortOption === false ? [] : defaultSortOption ?? getDefaultSortingForSchema(resolvedSchema), [defaultSortOption, resolvedSchema]);
7567
7615
  const metadataFields = (0, react.useMemo)(() => readMetadataFields(metadata?.fields), [metadata?.fields]);
7568
7616
  const columns = (0, react.useMemo)(() => createTableSchema(resolvedSchema), [resolvedSchema]);
7569
7617
  const [urlParams] = useQueryStates({
7570
7618
  page: parseAsInteger.withDefault(1),
7571
7619
  perPage: parseAsInteger.withDefault(10),
7572
- sort: getSortingStateParser().withDefault([]),
7620
+ sort: getSortingStateParser().withDefault(defaultSorting),
7573
7621
  joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
7574
7622
  search: parseAsString.withDefault("")
7575
7623
  }, { shallow: false });
@@ -7857,6 +7905,7 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
7857
7905
  },
7858
7906
  schema: resolvedSchema,
7859
7907
  fields: metadataFields,
7908
+ defaultSort: defaultSorting,
7860
7909
  modal,
7861
7910
  mutations: {
7862
7911
  isCreating: createMutation.isPending,
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime3 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime5 from "react/jsx-runtime";
2
2
  import { z } from "zod";
3
3
  import { JsonSchemaFormScope } from "@wordrhyme/formily-shadcn";
4
4
  import * as _tanstack_react_table0 from "@tanstack/react-table";
@@ -9,6 +9,12 @@ import { DropdownMenuTrigger, PopoverContent } from "@wordrhyme/shadcn";
9
9
  import { MultiCombobox, MultiComboboxOption, MultiComboboxProps, MultiComboboxTriggerRenderProps, Select, SelectMode, SelectOption, SelectProps, SelectSearchableDynamicProps, SelectSearchableMultipleProps, SelectSearchableProps, SelectSearchableSingleProps, SelectSimpleProps, SelectTriggerRenderProps } from "@wordrhyme/shadcn-ui";
10
10
  import { ClassValue } from "clsx";
11
11
 
12
+ //#region src/lib/default-sorting.d.ts
13
+ type AutoCrudSorting = Array<{
14
+ id: string;
15
+ desc: boolean;
16
+ }>;
17
+ //#endregion
12
18
  //#region src/hooks/use-auto-crud-resource.d.ts
13
19
  /**
14
20
  * Toast 适配器接口
@@ -103,6 +109,12 @@ interface UseAutoCrudResourceOptions<TSchema extends z.ZodObject<z.ZodRawShape>,
103
109
  total: number;
104
110
  hasMore: boolean;
105
111
  }>;
112
+ /**
113
+ * 默认排序。
114
+ * - undefined: schema 有 createdAt 时默认 createdAt desc
115
+ * - false: 不应用默认排序
116
+ */
117
+ defaultSort?: AutoCrudSorting | false;
106
118
  }
107
119
  /**
108
120
  * 导入结果类型(与服务端保持一致)
@@ -133,6 +145,8 @@ interface UseAutoCrudResourceReturn<TSchema extends z.ZodObject<z.ZodRawShape>,
133
145
  schema?: z.ZodObject<z.ZodRawShape>;
134
146
  /** Optional field config override from host metadata. */
135
147
  fields?: Fields;
148
+ /** Default sorting used by this resource's list query. */
149
+ defaultSort?: AutoCrudSorting;
136
150
  modal: ModalState<TListItem>;
137
151
  mutations: {
138
152
  isCreating: boolean;
@@ -381,7 +395,7 @@ declare function AutoTableActionBar<TData>({
381
395
  extraActions,
382
396
  actions,
383
397
  deleteConfirmation
384
- }: AutoTableActionBarProps<TData>): react_jsx_runtime3.JSX.Element;
398
+ }: AutoTableActionBarProps<TData>): react_jsx_runtime5.JSX.Element;
385
399
  //#endregion
386
400
  //#region src/lib/schema-bridge/types.d.ts
387
401
  /**
@@ -557,7 +571,7 @@ declare function AutoTable<T extends z.ZodObject<z.ZodRawShape>>({
557
571
  onSelectedCountChange,
558
572
  onSelectedRowsChange,
559
573
  getSelectedRows
560
- }: AutoTableProps<T>): react_jsx_runtime3.JSX.Element;
574
+ }: AutoTableProps<T>): react_jsx_runtime5.JSX.Element;
561
575
  //#endregion
562
576
  //#region src/i18n/locale.d.ts
563
577
  /**
@@ -1037,7 +1051,7 @@ declare function AutoCrudTable<TSchema extends z.ZodObject<z.ZodRawShape>>({
1037
1051
  toolbarActions,
1038
1052
  locale: localeProp,
1039
1053
  onCreate
1040
- }: AutoCrudTableProps<TSchema>): react_jsx_runtime3.JSX.Element;
1054
+ }: AutoCrudTableProps<TSchema>): react_jsx_runtime5.JSX.Element;
1041
1055
  //#endregion
1042
1056
  //#region src/components/auto-crud/auto-form.d.ts
1043
1057
  interface AutoFormProps<T extends z.ZodObject<z.ZodRawShape>> {
@@ -1076,7 +1090,7 @@ declare function AutoFormInner<T extends z.ZodObject<z.ZodRawShape>>({
1076
1090
  labelAlign,
1077
1091
  labelWidth,
1078
1092
  showSubmitButton
1079
- }: AutoFormProps<T>, ref: React.Ref<AutoFormRef>): react_jsx_runtime3.JSX.Element;
1093
+ }: AutoFormProps<T>, ref: React.Ref<AutoFormRef>): react_jsx_runtime5.JSX.Element;
1080
1094
  declare const AutoForm: <T extends z.ZodObject<z.ZodRawShape>>(props: AutoFormProps<T> & {
1081
1095
  ref?: React.Ref<AutoFormRef>;
1082
1096
  }) => ReturnType<typeof AutoFormInner>;
@@ -1392,7 +1406,7 @@ declare function AutoTableSimpleFilters<TData>({
1392
1406
  filters: externalFilters,
1393
1407
  onFiltersChange,
1394
1408
  leading
1395
- }: AutoTableSimpleFiltersProps<TData>): react_jsx_runtime3.JSX.Element | null;
1409
+ }: AutoTableSimpleFiltersProps<TData>): react_jsx_runtime5.JSX.Element | null;
1396
1410
  //#endregion
1397
1411
  //#region src/components/auto-crud/form-modal.d.ts
1398
1412
  type ModalVariant = "dialog" | "sheet";
@@ -1436,7 +1450,7 @@ declare function CrudFormModal<T extends z.ZodObject<z.ZodRawShape>>({
1436
1450
  labelAlign,
1437
1451
  labelWidth,
1438
1452
  className
1439
- }: CrudFormModalProps<T>): react_jsx_runtime3.JSX.Element;
1453
+ }: CrudFormModalProps<T>): react_jsx_runtime5.JSX.Element;
1440
1454
  //#endregion
1441
1455
  //#region src/components/auto-crud/import-dialog.d.ts
1442
1456
  interface ImportDialogProps {
@@ -1458,7 +1472,7 @@ declare function ImportDialog({
1458
1472
  columns,
1459
1473
  title,
1460
1474
  locale
1461
- }: ImportDialogProps): react_jsx_runtime3.JSX.Element;
1475
+ }: ImportDialogProps): react_jsx_runtime5.JSX.Element;
1462
1476
  //#endregion
1463
1477
  //#region src/components/auto-crud/export-dialog.d.ts
1464
1478
  type ExportMode = "selected" | "filtered";
@@ -1478,7 +1492,7 @@ declare function ExportDialog({
1478
1492
  selectedCount,
1479
1493
  onExport,
1480
1494
  canExportFiltered
1481
- }: ExportDialogProps): react_jsx_runtime3.JSX.Element;
1495
+ }: ExportDialogProps): react_jsx_runtime5.JSX.Element;
1482
1496
  //#endregion
1483
1497
  //#region src/components/data-table/data-table.d.ts
1484
1498
  interface DataTableProps<TData> extends React$1.ComponentProps<"div"> {
@@ -1491,7 +1505,7 @@ declare function DataTable<TData>({
1491
1505
  children,
1492
1506
  className,
1493
1507
  ...props
1494
- }: DataTableProps<TData>): react_jsx_runtime3.JSX.Element;
1508
+ }: DataTableProps<TData>): react_jsx_runtime5.JSX.Element;
1495
1509
  //#endregion
1496
1510
  //#region src/components/data-table/data-table-advanced-toolbar.d.ts
1497
1511
  interface DataTableAdvancedToolbarProps<TData> extends React$1.ComponentProps<"div"> {
@@ -1502,7 +1516,7 @@ declare function DataTableAdvancedToolbar<TData>({
1502
1516
  children,
1503
1517
  className,
1504
1518
  ...props
1505
- }: DataTableAdvancedToolbarProps<TData>): react_jsx_runtime3.JSX.Element;
1519
+ }: DataTableAdvancedToolbarProps<TData>): react_jsx_runtime5.JSX.Element;
1506
1520
  //#endregion
1507
1521
  //#region src/components/data-table/data-table-column-header.d.ts
1508
1522
  interface DataTableColumnHeaderProps<TData, TValue> extends React.ComponentProps<typeof DropdownMenuTrigger> {
@@ -1514,7 +1528,7 @@ declare function DataTableColumnHeader<TData, TValue>({
1514
1528
  label,
1515
1529
  className,
1516
1530
  ...props
1517
- }: DataTableColumnHeaderProps<TData, TValue>): react_jsx_runtime3.JSX.Element;
1531
+ }: DataTableColumnHeaderProps<TData, TValue>): react_jsx_runtime5.JSX.Element;
1518
1532
  //#endregion
1519
1533
  //#region src/components/data-table/data-table-faceted-filter.d.ts
1520
1534
  interface DataTableFacetedFilterProps<TData, TValue> {
@@ -1528,7 +1542,7 @@ declare function DataTableFacetedFilter<TData, TValue>({
1528
1542
  title,
1529
1543
  options,
1530
1544
  multiple
1531
- }: DataTableFacetedFilterProps<TData, TValue>): react_jsx_runtime3.JSX.Element;
1545
+ }: DataTableFacetedFilterProps<TData, TValue>): react_jsx_runtime5.JSX.Element;
1532
1546
  //#endregion
1533
1547
  //#region src/components/data-table/data-table-pagination.d.ts
1534
1548
  interface DataTablePaginationProps<TData> extends React.ComponentProps<"div"> {
@@ -1540,7 +1554,7 @@ declare function DataTablePagination<TData>({
1540
1554
  pageSizeOptions,
1541
1555
  className,
1542
1556
  ...props
1543
- }: DataTablePaginationProps<TData>): react_jsx_runtime3.JSX.Element;
1557
+ }: DataTablePaginationProps<TData>): react_jsx_runtime5.JSX.Element;
1544
1558
  //#endregion
1545
1559
  //#region src/components/data-table/data-table-toolbar.d.ts
1546
1560
  interface DataTableToolbarProps<TData> extends React$1.ComponentProps<"div"> {
@@ -1551,7 +1565,7 @@ declare function DataTableToolbar<TData>({
1551
1565
  children,
1552
1566
  className,
1553
1567
  ...props
1554
- }: DataTableToolbarProps<TData>): react_jsx_runtime3.JSX.Element;
1568
+ }: DataTableToolbarProps<TData>): react_jsx_runtime5.JSX.Element;
1555
1569
  //#endregion
1556
1570
  //#region src/components/data-table/data-table-view-options.d.ts
1557
1571
  interface DataTableViewOptionsProps<TData> extends React$1.ComponentProps<typeof PopoverContent> {
@@ -1562,7 +1576,7 @@ declare function DataTableViewOptions<TData>({
1562
1576
  table,
1563
1577
  disabled,
1564
1578
  ...props
1565
- }: DataTableViewOptionsProps<TData>): react_jsx_runtime3.JSX.Element;
1579
+ }: DataTableViewOptionsProps<TData>): react_jsx_runtime5.JSX.Element;
1566
1580
  //#endregion
1567
1581
  //#region src/lib/crud-actions.d.ts
1568
1582
  type CrudActionZone = 'toolbar' | 'row' | 'batch';
@@ -1644,7 +1658,7 @@ declare function useReadableFilters<TData>(columns: ColumnLike<TData>[], options
1644
1658
  */
1645
1659
  declare function createFormSchema<T extends z.ZodObject<z.ZodRawShape>>(schema: T, options?: CreateFormSchemaOptions): ISchema;
1646
1660
  /**
1647
- * 为编辑模式创建 Form Schema(排除 id, createdAt, updatedAt)
1661
+ * 为编辑模式创建 Form Schema(排除平台托管字段)
1648
1662
  */
1649
1663
  declare function createEditFormSchema<T extends z.ZodObject<z.ZodRawShape>>(schema: T, options?: Omit<CreateFormSchemaOptions, 'exclude'>): ISchema;
1650
1664
  //#endregion
package/dist/index.d.ts CHANGED
@@ -9,6 +9,12 @@ import { z } from "zod";
9
9
  import { JsonSchemaFormScope } from "@wordrhyme/formily-shadcn";
10
10
  import { ISchema } from "@formily/json-schema";
11
11
 
12
+ //#region src/lib/default-sorting.d.ts
13
+ type AutoCrudSorting = Array<{
14
+ id: string;
15
+ desc: boolean;
16
+ }>;
17
+ //#endregion
12
18
  //#region src/hooks/use-auto-crud-resource.d.ts
13
19
  /**
14
20
  * Toast 适配器接口
@@ -103,6 +109,12 @@ interface UseAutoCrudResourceOptions<TSchema extends z.ZodObject<z.ZodRawShape>,
103
109
  total: number;
104
110
  hasMore: boolean;
105
111
  }>;
112
+ /**
113
+ * 默认排序。
114
+ * - undefined: schema 有 createdAt 时默认 createdAt desc
115
+ * - false: 不应用默认排序
116
+ */
117
+ defaultSort?: AutoCrudSorting | false;
106
118
  }
107
119
  /**
108
120
  * 导入结果类型(与服务端保持一致)
@@ -133,6 +145,8 @@ interface UseAutoCrudResourceReturn<TSchema extends z.ZodObject<z.ZodRawShape>,
133
145
  schema?: z.ZodObject<z.ZodRawShape>;
134
146
  /** Optional field config override from host metadata. */
135
147
  fields?: Fields;
148
+ /** Default sorting used by this resource's list query. */
149
+ defaultSort?: AutoCrudSorting;
136
150
  modal: ModalState<TListItem>;
137
151
  mutations: {
138
152
  isCreating: boolean;
@@ -1644,7 +1658,7 @@ declare function useReadableFilters<TData>(columns: ColumnLike<TData>[], options
1644
1658
  */
1645
1659
  declare function createFormSchema<T extends z.ZodObject<z.ZodRawShape>>(schema: T, options?: CreateFormSchemaOptions): ISchema;
1646
1660
  /**
1647
- * 为编辑模式创建 Form Schema(排除 id, createdAt, updatedAt)
1661
+ * 为编辑模式创建 Form Schema(排除平台托管字段)
1648
1662
  */
1649
1663
  declare function createEditFormSchema<T extends z.ZodObject<z.ZodRawShape>>(schema: T, options?: Omit<CreateFormSchemaOptions, 'exclude'>): ISchema;
1650
1664
  //#endregion
package/dist/index.js CHANGED
@@ -2025,6 +2025,12 @@ function DataTableSortList({ table, disabled,...props }) {
2025
2025
  window.addEventListener("keydown", onKeyDown);
2026
2026
  return () => window.removeEventListener("keydown", onKeyDown);
2027
2027
  }, []);
2028
+ const onTriggerKeyDown = React.useCallback((event) => {
2029
+ if (REMOVE_SORT_SHORTCUTS.includes(event.key.toLowerCase()) && sorting.length > 0) {
2030
+ event.preventDefault();
2031
+ onSortingReset();
2032
+ }
2033
+ }, [sorting.length, onSortingReset]);
2028
2034
  return /* @__PURE__ */ jsxs(Sortable, {
2029
2035
  value: sorting,
2030
2036
  onValueChange: onSortingChange,
@@ -2036,24 +2042,17 @@ function DataTableSortList({ table, disabled,...props }) {
2036
2042
  asChild: true,
2037
2043
  children: /* @__PURE__ */ jsxs(Button, {
2038
2044
  variant: "outline",
2039
- size: "sm",
2040
- className: "font-normal",
2041
- onKeyDown: React.useCallback((event) => {
2042
- if (REMOVE_SORT_SHORTCUTS.includes(event.key.toLowerCase()) && sorting.length > 0) {
2043
- event.preventDefault();
2044
- onSortingReset();
2045
- }
2046
- }, [sorting.length, onSortingReset]),
2045
+ size: "icon-sm",
2046
+ "aria-label": "Sort rows",
2047
+ title: "Sort rows",
2048
+ className: cn(sorting.length > 0 && "w-auto gap-1 px-2"),
2049
+ onKeyDown: onTriggerKeyDown,
2047
2050
  disabled,
2048
- children: [
2049
- /* @__PURE__ */ jsx(ArrowDownUp, { className: "text-muted-foreground" }),
2050
- "Sort",
2051
- sorting.length > 0 && /* @__PURE__ */ jsx(Badge, {
2052
- variant: "secondary",
2053
- className: "h-[18.24px] rounded-[3.2px] px-[5.12px] font-mono font-normal text-[10.4px]",
2054
- children: sorting.length
2055
- })
2056
- ]
2051
+ children: [/* @__PURE__ */ jsx(ArrowDownUp, { className: "text-muted-foreground" }), sorting.length > 0 && /* @__PURE__ */ jsx(Badge, {
2052
+ variant: "secondary",
2053
+ className: "h-[18.24px] rounded-[3.2px] px-[5.12px] font-mono font-normal text-[10.4px]",
2054
+ children: sorting.length
2055
+ })]
2057
2056
  })
2058
2057
  }), /* @__PURE__ */ jsxs(PopoverContent, {
2059
2058
  "aria-labelledby": labelId,
@@ -2223,14 +2222,15 @@ function DataTableViewOptions({ table, disabled,...props }) {
2223
2222
  const columns = React.useMemo(() => table.getAllColumns().filter((column) => typeof column.accessorFn !== "undefined" && column.getCanHide()), [table]);
2224
2223
  return /* @__PURE__ */ jsxs(Popover, { children: [/* @__PURE__ */ jsx(PopoverTrigger, {
2225
2224
  asChild: true,
2226
- children: /* @__PURE__ */ jsxs(Button, {
2225
+ children: /* @__PURE__ */ jsx(Button, {
2227
2226
  "aria-label": "Toggle columns",
2227
+ title: "Toggle columns",
2228
2228
  role: "combobox",
2229
2229
  variant: "outline",
2230
- size: "sm",
2231
- className: "ml-auto flex h-8 font-normal",
2230
+ size: "icon-sm",
2231
+ className: "ml-auto",
2232
2232
  disabled,
2233
- children: [/* @__PURE__ */ jsx(Settings2, { className: "text-muted-foreground" }), "View"]
2233
+ children: /* @__PURE__ */ jsx(Settings2, { className: "text-muted-foreground" })
2234
2234
  })
2235
2235
  }), /* @__PURE__ */ jsx(PopoverContent, {
2236
2236
  className: "w-44 p-0",
@@ -3937,7 +3937,7 @@ const filterModeConfig = {
3937
3937
  tooltip: "Linear-style command filters"
3938
3938
  }
3939
3939
  };
3940
- function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode = "simple", search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, deleteConfirmation, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
3940
+ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode, search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, deleteConfirmation, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
3941
3941
  const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
3942
3942
  const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
3943
3943
  const showToggle = modes.length > 1;
@@ -4012,9 +4012,9 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
4012
4012
  asChild: true,
4013
4013
  children: /* @__PURE__ */ jsx(Button, {
4014
4014
  variant: "outline",
4015
- size: "sm",
4016
- className: "h-8 w-8 p-0",
4015
+ size: "icon-sm",
4017
4016
  "aria-label": `Switch filter mode, current: ${filterModeConfig[currentMode].label}`,
4017
+ title: filterModeConfig[currentMode].tooltip,
4018
4018
  children: (() => {
4019
4019
  const Icon = filterModeConfig[currentMode].icon;
4020
4020
  return /* @__PURE__ */ jsx(Icon, { className: "size-4 text-muted-foreground" });
@@ -4081,22 +4081,15 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
4081
4081
  children: [/* @__PURE__ */ jsxs("div", {
4082
4082
  className: "flex min-h-[40px] min-w-0 flex-1 items-start gap-2",
4083
4083
  "data-filter-parent": true,
4084
- children: [
4085
- currentMode !== "simple" && searchInput,
4086
- currentMode !== "simple" && /* @__PURE__ */ jsx(DataTableSortList, {
4087
- table,
4088
- align: "start"
4089
- }),
4090
- filtersContent
4091
- ]
4084
+ children: [currentMode !== "simple" && searchInput, filtersContent]
4092
4085
  }), /* @__PURE__ */ jsxs("div", {
4093
4086
  className: "flex items-center gap-2",
4094
4087
  children: [
4095
- currentMode === "simple" && /* @__PURE__ */ jsx(DataTableSortList, {
4088
+ FilterModeSelect,
4089
+ /* @__PURE__ */ jsx(DataTableSortList, {
4096
4090
  table,
4097
4091
  align: "end"
4098
4092
  }),
4099
- FilterModeSelect,
4100
4093
  /* @__PURE__ */ jsx(DataTableViewOptions, {
4101
4094
  table,
4102
4095
  align: "end"
@@ -4177,6 +4170,15 @@ function FormModal({ open, onOpenChange, title, description, children, variant =
4177
4170
 
4178
4171
  //#endregion
4179
4172
  //#region src/lib/schema-bridge/zod-to-formily.ts
4173
+ const DEFAULT_FORM_MANAGED_FIELDS = [
4174
+ "id",
4175
+ "createdAt",
4176
+ "updatedAt",
4177
+ "createdBy",
4178
+ "createdByType",
4179
+ "updatedBy",
4180
+ "updatedByType"
4181
+ ];
4180
4182
  /**
4181
4183
  * 将字符串转为人类可读格式
4182
4184
  */
@@ -4259,16 +4261,12 @@ function createFormSchema(schema, options) {
4259
4261
  };
4260
4262
  }
4261
4263
  /**
4262
- * 为编辑模式创建 Form Schema(排除 id, createdAt, updatedAt)
4264
+ * 为编辑模式创建 Form Schema(排除平台托管字段)
4263
4265
  */
4264
4266
  function createEditFormSchema(schema, options) {
4265
4267
  return createFormSchema(schema, {
4266
4268
  ...options,
4267
- exclude: [
4268
- "id",
4269
- "createdAt",
4270
- "updatedAt"
4271
- ]
4269
+ exclude: [...DEFAULT_FORM_MANAGED_FIELDS]
4272
4270
  });
4273
4271
  }
4274
4272
 
@@ -5602,6 +5600,15 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title, local
5602
5600
  });
5603
5601
  }
5604
5602
 
5603
+ //#endregion
5604
+ //#region src/lib/default-sorting.ts
5605
+ function getDefaultSortingForSchema(schema) {
5606
+ return Object.prototype.hasOwnProperty.call(schema.shape, "createdAt") ? [{
5607
+ id: "createdAt",
5608
+ desc: true
5609
+ }] : [];
5610
+ }
5611
+
5605
5612
  //#endregion
5606
5613
  //#region src/lib/crud-actions.ts
5607
5614
  const entries = /* @__PURE__ */ new Map();
@@ -5751,6 +5758,29 @@ const crudActions = {
5751
5758
 
5752
5759
  //#endregion
5753
5760
  //#region src/components/auto-crud/auto-crud-table.tsx
5761
+ const DEFAULT_IMPORT_MANAGED_FIELDS = [
5762
+ "createdAt",
5763
+ "updatedAt",
5764
+ "createdBy",
5765
+ "createdByType",
5766
+ "updatedBy",
5767
+ "updatedByType"
5768
+ ];
5769
+ const DEFAULT_HIDDEN_AUDIT_FIELDS = [
5770
+ "createdBy",
5771
+ "createdByType",
5772
+ "updatedBy",
5773
+ "updatedByType"
5774
+ ];
5775
+ function isDefaultHiddenAuditField(key) {
5776
+ return DEFAULT_HIDDEN_AUDIT_FIELDS.includes(key);
5777
+ }
5778
+ function isFieldTableExplicitlyVisible(config) {
5779
+ return config?.hidden === false || config?.table !== false && typeof config?.table === "object" && config.table.hidden === false;
5780
+ }
5781
+ function isTableOverrideExplicitlyVisible(config) {
5782
+ return config?.hidden === false;
5783
+ }
5754
5784
  let autoCrudToolbarResolver = null;
5755
5785
  function setToolbarResolver(resolver) {
5756
5786
  autoCrudToolbarResolver = resolver;
@@ -6202,10 +6232,18 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState) {
6202
6232
  /**
6203
6233
  * 从统一配置生成隐藏列列表
6204
6234
  */
6205
- function buildHiddenColumns(fields, legacyHidden, denyFields) {
6206
- const hidden = new Set([...legacyHidden ?? [], ...denyFields ?? []]);
6207
- if (fields) {
6208
- for (const [key, config] of Object.entries(fields)) if (config.hidden) hidden.add(key);
6235
+ function buildHiddenColumns(fields, legacyHidden, denyFields, legacyOverrides) {
6236
+ const legacyHiddenSet = new Set(legacyHidden ?? []);
6237
+ const denySet = new Set(denyFields ?? []);
6238
+ const hidden = new Set([
6239
+ ...DEFAULT_HIDDEN_AUDIT_FIELDS,
6240
+ ...legacyHiddenSet,
6241
+ ...denySet
6242
+ ]);
6243
+ for (const key of DEFAULT_HIDDEN_AUDIT_FIELDS) if (!legacyHiddenSet.has(key) && !denySet.has(key) && isTableOverrideExplicitlyVisible(legacyOverrides?.[key])) hidden.delete(key);
6244
+ if (fields) for (const [key, config] of Object.entries(fields)) {
6245
+ if (isDefaultHiddenAuditField(key) && !legacyHiddenSet.has(key) && !denySet.has(key) && isFieldTableExplicitlyVisible(config)) hidden.delete(key);
6246
+ if (config.hidden) hidden.add(key);
6209
6247
  else if (config.table === false) hidden.add(key);
6210
6248
  else if (config.table && typeof config.table === "object" && config.table.hidden) hidden.add(key);
6211
6249
  }
@@ -6309,7 +6347,10 @@ function ViewModal({ open, onOpenChange, variant, data, schema, fields: fieldCon
6309
6347
  className: "grid gap-4 py-4",
6310
6348
  children: Object.entries(shape).filter(([key]) => {
6311
6349
  if (denySet.has(key)) return false;
6312
- return !(fieldConfig?.[key])?.hidden;
6350
+ const config = fieldConfig?.[key];
6351
+ if (config?.hidden) return false;
6352
+ if (isDefaultHiddenAuditField(key) && !isFieldTableExplicitlyVisible(config)) return false;
6353
+ return true;
6313
6354
  }).map(([key, fieldSchema]) => {
6314
6355
  const parsed = parseZodField(fieldSchema);
6315
6356
  const label = fieldConfig?.[key]?.label ?? humanize(key);
@@ -6522,7 +6563,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
6522
6563
  const resolvedToolbarActions = resolveToolbarActionsWithResolver(id, registryToolbarActions, toolbarContext);
6523
6564
  const importColumns = React.useMemo(() => {
6524
6565
  const shape = resolvedSchema.shape;
6525
- const denySet = new Set(denyFields ?? []);
6566
+ const denySet = new Set([...DEFAULT_IMPORT_MANAGED_FIELDS, ...denyFields ?? []]);
6526
6567
  return Object.keys(shape).filter((key) => !denySet.has(key));
6527
6568
  }, [resolvedSchema, denyFields]);
6528
6569
  const handleExport = React.useCallback(async (mode) => {
@@ -6561,15 +6602,21 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
6561
6602
  tableConfig?.overrides,
6562
6603
  dynamicFilterOptions
6563
6604
  ]);
6605
+ const defaultSort = React.useMemo(() => resource.defaultSort ?? tableConfig?.defaultSort ?? getDefaultSortingForSchema(resolvedSchema), [
6606
+ resource.defaultSort,
6607
+ resolvedSchema,
6608
+ tableConfig?.defaultSort
6609
+ ]);
6564
6610
  const formOverrides = React.useMemo(() => buildFormOverrides(resolvedFields, formConfig?.overrides, denyFields), [
6565
6611
  resolvedFields,
6566
6612
  formConfig?.overrides,
6567
6613
  denyFields
6568
6614
  ]);
6569
- const hiddenColumns = React.useMemo(() => buildHiddenColumns(resolvedFields, tableConfig?.hidden, denyFields), [
6615
+ const hiddenColumns = React.useMemo(() => buildHiddenColumns(resolvedFields, tableConfig?.hidden, denyFields, tableConfig?.overrides), [
6570
6616
  resolvedFields,
6571
6617
  tableConfig?.hidden,
6572
- denyFields
6618
+ denyFields,
6619
+ tableConfig?.overrides
6573
6620
  ]);
6574
6621
  const searchConfig = React.useMemo(() => {
6575
6622
  const tableSearch = tableConfig?.search;
@@ -6717,7 +6764,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
6717
6764
  deleteConfirmation: locale.bulkDeleteModal,
6718
6765
  enableExport: canExport,
6719
6766
  showDefaultExport: false,
6720
- initialSorting: tableConfig?.defaultSort,
6767
+ initialSorting: defaultSort,
6721
6768
  onSelectedRowsChange: handleSelectedRowsChange,
6722
6769
  getSelectedRows: getSelectedRowsRef
6723
6770
  }),
@@ -7519,7 +7566,7 @@ function modalReducer(state, action$1) {
7519
7566
  * Hook 主函数
7520
7567
  */
7521
7568
  function useAutoCrudResource({ router, schema, query: queryTransform, options = {} }) {
7522
- const { idKey = "id", defaultVariant = "dialog", hooks, toast: toastAdapter, exportFetcher } = options;
7569
+ const { idKey = "id", defaultVariant = "dialog", hooks, toast: toastAdapter, exportFetcher, defaultSort: defaultSortOption } = options;
7523
7570
  const toast$1 = useMemo(() => toastAdapter === false ? noopToastAdapter : toastAdapter ?? defaultToastAdapter, [toastAdapter]);
7524
7571
  const hooksRef = useRef(hooks);
7525
7572
  useEffect(() => {
@@ -7527,12 +7574,13 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
7527
7574
  }, [hooks]);
7528
7575
  const metadata = (router.meta?.useQuery(void 0, { staleTime: 3e4 }))?.data;
7529
7576
  const resolvedSchema = useMemo(() => mergeMetadataSchema(schema, metadata?.schema), [schema, metadata?.schema]);
7577
+ const defaultSorting = useMemo(() => defaultSortOption === false ? [] : defaultSortOption ?? getDefaultSortingForSchema(resolvedSchema), [defaultSortOption, resolvedSchema]);
7530
7578
  const metadataFields = useMemo(() => readMetadataFields(metadata?.fields), [metadata?.fields]);
7531
7579
  const columns = useMemo(() => createTableSchema(resolvedSchema), [resolvedSchema]);
7532
7580
  const [urlParams] = useQueryStates({
7533
7581
  page: parseAsInteger.withDefault(1),
7534
7582
  perPage: parseAsInteger.withDefault(10),
7535
- sort: getSortingStateParser().withDefault([]),
7583
+ sort: getSortingStateParser().withDefault(defaultSorting),
7536
7584
  joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
7537
7585
  search: parseAsString.withDefault("")
7538
7586
  }, { shallow: false });
@@ -7820,6 +7868,7 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
7820
7868
  },
7821
7869
  schema: resolvedSchema,
7822
7870
  fields: metadataFields,
7871
+ defaultSort: defaultSorting,
7823
7872
  modal,
7824
7873
  mutations: {
7825
7874
  isCreating: createMutation.isPending,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wordrhyme/auto-crud",
3
3
  "type": "module",
4
- "version": "1.3.5",
4
+ "version": "1.3.8",
5
5
  "description": "Schema-first CRUD components with auto-generated tables and forms",
6
6
  "author": "wordrhyme",
7
7
  "license": "MIT",
@@ -62,9 +62,9 @@
62
62
  "nanoid": "^5.1.6",
63
63
  "tailwind-merge": "^3.5.0",
64
64
  "vaul": "^1.1.2",
65
+ "@wordrhyme/formily-shadcn": "1.12.9",
65
66
  "@wordrhyme/shadcn": "1.3.2",
66
- "@wordrhyme/shadcn-ui": "1.32.4",
67
- "@wordrhyme/formily-shadcn": "1.12.9"
67
+ "@wordrhyme/shadcn-ui": "1.32.4"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@tanstack/react-query": "^5.90.15",
@@ -83,9 +83,9 @@
83
83
  "typescript": "^5.9.3",
84
84
  "vitest": "^3.2.4",
85
85
  "@internal/eslint-config": "0.3.0",
86
+ "@internal/prettier-config": "0.0.1",
86
87
  "@internal/tsconfig": "0.1.0",
87
88
  "@internal/tsdown-config": "0.1.0",
88
- "@internal/prettier-config": "0.0.1",
89
89
  "@internal/vitest-config": "0.1.0"
90
90
  },
91
91
  "prettier": "@internal/prettier-config",