@wordrhyme/auto-crud 1.0.0 → 1.0.1

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/dist/index.cjs CHANGED
@@ -1450,7 +1450,12 @@ function DataTableFilterList({ table, debounceMs = DEBOUNCE_MS$2, throttleMs = T
1450
1450
  const [open, setOpen] = react.useState(false);
1451
1451
  const addButtonRef = react.useRef(null);
1452
1452
  const columns = react.useMemo(() => {
1453
- return table.getAllColumns().filter((column) => column.columnDef.enableColumnFilter);
1453
+ return table.getAllColumns().filter((column) => {
1454
+ if (!column.getCanFilter()) return false;
1455
+ const modes = column.columnDef.meta?.modes;
1456
+ if (modes && !modes.includes("advanced")) return false;
1457
+ return true;
1458
+ });
1454
1459
  }, [table]);
1455
1460
  const [filters, setFilters] = useReadableFilters(columns, { debounceMs });
1456
1461
  const debouncedSetFilters = useDebouncedCallback(setFilters, debounceMs);
@@ -1932,7 +1937,12 @@ const REMOVE_FILTER_SHORTCUTS = ["backspace", "delete"];
1932
1937
  function DataTableFilterMenu({ table, debounceMs = DEBOUNCE_MS$1, throttleMs = THROTTLE_MS$1, shallow = true, disabled,...props }) {
1933
1938
  const id = react.useId();
1934
1939
  const columns = react.useMemo(() => {
1935
- return table.getAllColumns().filter((column) => column.columnDef.enableColumnFilter);
1940
+ return table.getAllColumns().filter((column) => {
1941
+ if (!column.columnDef.enableColumnFilter) return false;
1942
+ const modes = column.columnDef.meta?.modes;
1943
+ if (modes && !modes.includes("command")) return false;
1944
+ return true;
1945
+ });
1936
1946
  }, [table]);
1937
1947
  const [open, setOpen] = react.useState(false);
1938
1948
  const [selectedColumn, setSelectedColumn] = react.useState(null);
@@ -2689,7 +2699,7 @@ function DataTableViewOptions({ table, disabled,...props }) {
2689
2699
  //#endregion
2690
2700
  //#region src/components/auto-crud/auto-table-simple-filters.tsx
2691
2701
  function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilters, onFiltersChange }) {
2692
- const columns = react.useMemo(() => table.getAllColumns().filter((col) => col.columnDef.enableColumnFilter), [table]);
2702
+ const columns = react.useMemo(() => table.getAllColumns().filter((col) => col.getCanFilter()), [table]);
2693
2703
  const queryStateOptions = table.options.meta?.queryStateOptions;
2694
2704
  const [queryFilters, setQueryFilters] = useReadableFilters(columns, {
2695
2705
  ...queryStateOptions,
@@ -2709,9 +2719,10 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
2709
2719
  react.useEffect(() => {
2710
2720
  setMounted(true);
2711
2721
  }, []);
2712
- const getFilterValue = (columnId) => {
2713
- return filters.find((f) => f.id === columnId)?.value;
2714
- };
2722
+ const filterMap = react.useMemo(() => new Map(filters.map((f) => [f.id, f])), [filters]);
2723
+ const getFilterValue = react.useCallback((columnId) => {
2724
+ return filterMap.get(columnId)?.value;
2725
+ }, [filterMap]);
2715
2726
  const updateFilter = react.useCallback((columnId, value) => {
2716
2727
  const column = columns.find((c) => c.id === columnId);
2717
2728
  if (!column) return;
@@ -2734,7 +2745,14 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
2734
2745
  setFilters
2735
2746
  ]);
2736
2747
  const hasFilters = filters.length > 0;
2737
- const filterColumns = react.useMemo(() => columns.filter((col) => col.columnDef.meta?.variant && col.columnDef.enableColumnFilter !== false), [columns]);
2748
+ const filterColumns = react.useMemo(() => columns.filter((col) => {
2749
+ const meta = col.columnDef.meta;
2750
+ const enableFilter = col.columnDef.enableColumnFilter !== false;
2751
+ if (!meta?.variant || !enableFilter) return false;
2752
+ const modes = meta.modes;
2753
+ if (modes && !modes.includes("simple")) return false;
2754
+ return true;
2755
+ }), [columns]);
2738
2756
  const [expanded, setExpanded] = react.useState(false);
2739
2757
  const [visibleCount, setVisibleCount] = react.useState(null);
2740
2758
  const containerRef = react.useRef(null);
@@ -2874,7 +2892,7 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
2874
2892
  }
2875
2893
  function SimpleFacetedFilter({ title, options, multiple, value, onChange }) {
2876
2894
  const [open, setOpen] = react.useState(false);
2877
- const selectedValues = new Set(value);
2895
+ const selectedValues = react.useMemo(() => new Set(value), [value]);
2878
2896
  const onItemSelect = (option, isSelected) => {
2879
2897
  if (multiple) {
2880
2898
  const newValues = new Set(selectedValues);
@@ -2905,6 +2923,12 @@ function SimpleFacetedFilter({ title, options, multiple, value, onChange }) {
2905
2923
  tabIndex: 0,
2906
2924
  className: "rounded-sm opacity-70 hover:opacity-100",
2907
2925
  onClick: onReset,
2926
+ onKeyDown: (e) => {
2927
+ if (e.key === "Enter" || e.key === " ") {
2928
+ e.preventDefault();
2929
+ onReset(e);
2930
+ }
2931
+ },
2908
2932
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.XCircle, {})
2909
2933
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.PlusCircle, {}),
2910
2934
  title,
@@ -3012,6 +3036,12 @@ function SimpleSliderFilter({ title, range, unit, value, onChange }) {
3012
3036
  tabIndex: 0,
3013
3037
  className: "rounded-sm opacity-70 hover:opacity-100",
3014
3038
  onClick: onReset,
3039
+ onKeyDown: (e) => {
3040
+ if (e.key === "Enter" || e.key === " ") {
3041
+ e.preventDefault();
3042
+ onReset(e);
3043
+ }
3044
+ },
3015
3045
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.XCircle, {})
3016
3046
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.PlusCircle, {}),
3017
3047
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: title }),
@@ -3135,6 +3165,12 @@ function SimpleDateFilter({ title, multiple, value, onChange }) {
3135
3165
  tabIndex: 0,
3136
3166
  className: "rounded-sm opacity-70 hover:opacity-100",
3137
3167
  onClick: onReset,
3168
+ onKeyDown: (e) => {
3169
+ if (e.key === "Enter" || e.key === " ") {
3170
+ e.preventDefault();
3171
+ onReset(e);
3172
+ }
3173
+ },
3138
3174
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.XCircle, {})
3139
3175
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.CalendarIcon, {}),
3140
3176
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: title }),
@@ -3747,33 +3783,47 @@ function inferFilterVariantByFieldName(fieldName) {
3747
3783
 
3748
3784
  //#endregion
3749
3785
  //#region src/lib/schema-bridge/zod-to-columns.tsx
3786
+ const parsedFieldCache = /* @__PURE__ */ new WeakMap();
3787
+ const baseTableSchemaCache = /* @__PURE__ */ new WeakMap();
3750
3788
  /**
3751
3789
  * 解析 Zod 字段类型
3752
3790
  */
3753
3791
  function parseZodField(schema) {
3792
+ const cached = parsedFieldCache.get(schema);
3793
+ if (cached) return cached;
3794
+ const finalize = (result) => {
3795
+ parsedFieldCache.set(schema, result);
3796
+ return result;
3797
+ };
3754
3798
  const def = schema._zod?.def ?? schema._def;
3755
- const testNull = schema.safeParse(null);
3756
- const required = !schema.safeParse(void 0).success && !testNull.success;
3757
3799
  const typeName = def?.typeName;
3758
- if (def?.type === "nullable" || def?.type === "optional" || typeName === "ZodNullable" || typeName === "ZodOptional") {
3800
+ const isOptional = def?.type === "optional" || typeName === "ZodOptional";
3801
+ const isNullable = def?.type === "nullable" || typeName === "ZodNullable";
3802
+ if (isOptional || isNullable) {
3759
3803
  const innerType = def?.innerType;
3760
- if (innerType) return {
3804
+ if (innerType) return finalize({
3761
3805
  ...parseZodField(innerType),
3762
3806
  required: false
3763
- };
3807
+ });
3808
+ }
3809
+ let required;
3810
+ if (isOptional || isNullable) required = false;
3811
+ else {
3812
+ const testNull = schema.safeParse(null);
3813
+ required = !schema.safeParse(void 0).success && !testNull.success;
3764
3814
  }
3765
- if (def?.type === "boolean") return {
3815
+ if (def?.type === "boolean") return finalize({
3766
3816
  type: "boolean",
3767
3817
  required
3768
- };
3769
- if (def?.type === "number") return {
3818
+ });
3819
+ if (def?.type === "number") return finalize({
3770
3820
  type: "number",
3771
3821
  required
3772
- };
3773
- if (def?.type === "date") return {
3822
+ });
3823
+ if (def?.type === "date") return finalize({
3774
3824
  type: "date",
3775
3825
  required
3776
- };
3826
+ });
3777
3827
  if (def?.type === "enum") {
3778
3828
  let enumValues$1;
3779
3829
  if (def?.entries) {
@@ -3784,20 +3834,20 @@ function parseZodField(schema) {
3784
3834
  const values = def.values;
3785
3835
  if (Array.isArray(values)) enumValues$1 = values.map(String);
3786
3836
  }
3787
- if (enumValues$1 && enumValues$1.length > 0) return {
3837
+ if (enumValues$1 && enumValues$1.length > 0) return finalize({
3788
3838
  type: "enum",
3789
3839
  required,
3790
3840
  enumValues: enumValues$1
3791
- };
3841
+ });
3792
3842
  }
3793
- if (def?.type === "string") return {
3843
+ if (def?.type === "string") return finalize({
3794
3844
  type: "string",
3795
3845
  required
3796
- };
3797
- if (typeName === "ZodBoolean") return {
3846
+ });
3847
+ if (typeName === "ZodBoolean") return finalize({
3798
3848
  type: "boolean",
3799
3849
  required
3800
- };
3850
+ });
3801
3851
  let enumValues;
3802
3852
  if (def?.entries) {
3803
3853
  const entries = def.entries;
@@ -3807,51 +3857,51 @@ function parseZodField(schema) {
3807
3857
  const values = def.values;
3808
3858
  if (Array.isArray(values)) enumValues = values.map(String);
3809
3859
  }
3810
- if (enumValues && Array.isArray(enumValues) && enumValues.length > 0) return {
3860
+ if (enumValues && Array.isArray(enumValues) && enumValues.length > 0) return finalize({
3811
3861
  type: "enum",
3812
3862
  required,
3813
3863
  enumValues
3814
- };
3815
- if (typeName === "ZodNumber") return {
3864
+ });
3865
+ if (typeName === "ZodNumber") return finalize({
3816
3866
  type: "number",
3817
3867
  required
3818
- };
3819
- if (typeName === "ZodDate") return {
3868
+ });
3869
+ if (typeName === "ZodDate") return finalize({
3820
3870
  type: "date",
3821
3871
  required
3822
- };
3823
- if (typeName === "ZodArray") return {
3872
+ });
3873
+ if (typeName === "ZodArray") return finalize({
3824
3874
  type: "array",
3825
3875
  required
3826
- };
3827
- if (typeName === "ZodObject") return {
3876
+ });
3877
+ if (typeName === "ZodObject") return finalize({
3828
3878
  type: "object",
3829
3879
  required
3830
- };
3880
+ });
3831
3881
  const testString = schema.safeParse("test");
3832
3882
  const testNumber = schema.safeParse(123);
3833
3883
  const testBoolean = schema.safeParse(true);
3834
3884
  const testDate = schema.safeParse(17040672e5);
3835
- if (testBoolean.success && !testString.success && !testNumber.success) return {
3885
+ if (testBoolean.success && !testString.success && !testNumber.success) return finalize({
3836
3886
  type: "boolean",
3837
3887
  required
3838
- };
3839
- if (testDate.success && !testString.success) return {
3888
+ });
3889
+ if (testDate.success && !testString.success) return finalize({
3840
3890
  type: "date",
3841
3891
  required
3842
- };
3843
- if (testNumber.success && !testString.success) return {
3892
+ });
3893
+ if (testNumber.success && !testString.success) return finalize({
3844
3894
  type: "number",
3845
3895
  required
3846
- };
3847
- if (schema.safeParse([]).success && !testString.success) return {
3896
+ });
3897
+ if (schema.safeParse([]).success && !testString.success) return finalize({
3848
3898
  type: "array",
3849
3899
  required
3850
- };
3851
- return {
3900
+ });
3901
+ return finalize({
3852
3902
  type: "string",
3853
3903
  required
3854
- };
3904
+ });
3855
3905
  }
3856
3906
  /**
3857
3907
  * 渲染单元格内容
@@ -3893,9 +3943,14 @@ function renderCell(value, type) {
3893
3943
  * 从 Zod Schema 创建 Table Schema (ColumnDef 数组)
3894
3944
  */
3895
3945
  function createTableSchema(schema, options) {
3946
+ const { overrides, exclude = [] } = options ?? {};
3947
+ const canCache = !(!!overrides && Object.keys(overrides).length > 0) && exclude.length === 0;
3948
+ if (canCache) {
3949
+ const cached = baseTableSchemaCache.get(schema);
3950
+ if (cached) return [...cached];
3951
+ }
3896
3952
  const shape = schema.shape;
3897
3953
  const columns = [];
3898
- const { overrides, exclude = [] } = options ?? {};
3899
3954
  for (const [key, fieldSchema] of Object.entries(shape)) {
3900
3955
  if (exclude.includes(key)) continue;
3901
3956
  const override = overrides?.[key];
@@ -3930,6 +3985,7 @@ function createTableSchema(schema, options) {
3930
3985
  ...restOverride
3931
3986
  });
3932
3987
  }
3988
+ if (canCache) baseTableSchemaCache.set(schema, columns);
3933
3989
  return columns;
3934
3990
  }
3935
3991
  /**
@@ -4446,6 +4502,13 @@ function useDataTable(props) {
4446
4502
  filterableColumns,
4447
4503
  enableAdvancedFilter
4448
4504
  ]);
4505
+ const getCoreRowModelFn = react.useMemo(() => (0, __tanstack_react_table.getCoreRowModel)(), []);
4506
+ const getFilteredRowModelFn = react.useMemo(() => (0, __tanstack_react_table.getFilteredRowModel)(), []);
4507
+ const getPaginationRowModelFn = react.useMemo(() => (0, __tanstack_react_table.getPaginationRowModel)(), []);
4508
+ const getSortedRowModelFn = react.useMemo(() => (0, __tanstack_react_table.getSortedRowModel)(), []);
4509
+ const getFacetedRowModelFn = react.useMemo(() => (0, __tanstack_react_table.getFacetedRowModel)(), []);
4510
+ const getFacetedUniqueValuesFn = react.useMemo(() => (0, __tanstack_react_table.getFacetedUniqueValues)(), []);
4511
+ const getFacetedMinMaxValuesFn = react.useMemo(() => (0, __tanstack_react_table.getFacetedMinMaxValues)(), []);
4449
4512
  const table = (0, __tanstack_react_table.useReactTable)({
4450
4513
  ...tableProps,
4451
4514
  columns,
@@ -4468,13 +4531,13 @@ function useDataTable(props) {
4468
4531
  onSortingChange,
4469
4532
  onColumnFiltersChange,
4470
4533
  onColumnVisibilityChange: setColumnVisibility,
4471
- getCoreRowModel: (0, __tanstack_react_table.getCoreRowModel)(),
4472
- getFilteredRowModel: (0, __tanstack_react_table.getFilteredRowModel)(),
4473
- getPaginationRowModel: (0, __tanstack_react_table.getPaginationRowModel)(),
4474
- getSortedRowModel: (0, __tanstack_react_table.getSortedRowModel)(),
4475
- getFacetedRowModel: (0, __tanstack_react_table.getFacetedRowModel)(),
4476
- getFacetedUniqueValues: (0, __tanstack_react_table.getFacetedUniqueValues)(),
4477
- getFacetedMinMaxValues: (0, __tanstack_react_table.getFacetedMinMaxValues)(),
4534
+ getCoreRowModel: getCoreRowModelFn,
4535
+ getFilteredRowModel: getFilteredRowModelFn,
4536
+ getPaginationRowModel: getPaginationRowModelFn,
4537
+ getSortedRowModel: getSortedRowModelFn,
4538
+ getFacetedRowModel: getFacetedRowModelFn,
4539
+ getFacetedUniqueValues: getFacetedUniqueValuesFn,
4540
+ getFacetedMinMaxValues: getFacetedMinMaxValuesFn,
4478
4541
  manualPagination: true,
4479
4542
  manualSorting: true,
4480
4543
  manualFiltering: true,
@@ -4505,6 +4568,11 @@ function useDataTable(props) {
4505
4568
 
4506
4569
  //#endregion
4507
4570
  //#region src/components/auto-crud/auto-table.tsx
4571
+ const DEFAULT_MODES = [
4572
+ "simple",
4573
+ "advanced",
4574
+ "command"
4575
+ ];
4508
4576
  /** 过滤模式配置 */
4509
4577
  const filterModeConfig = {
4510
4578
  simple: {
@@ -4524,11 +4592,7 @@ const filterModeConfig = {
4524
4592
  }
4525
4593
  };
4526
4594
  function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode = "simple", onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, initialSorting, enableExport = true, onSelectedCountChange, getSelectedRows }) {
4527
- const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : [
4528
- "simple",
4529
- "advanced",
4530
- "command"
4531
- ];
4595
+ const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
4532
4596
  const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
4533
4597
  const showToggle = modes.length > 1;
4534
4598
  const { table, shallow, debounceMs, throttleMs } = useDataTable({
@@ -4550,13 +4614,18 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
4550
4614
  ]),
4551
4615
  pageCount,
4552
4616
  enableAdvancedFilter: true,
4553
- initialState: {
4617
+ initialState: (0, react.useMemo)(() => ({
4554
4618
  sorting: initialSorting,
4555
4619
  columnPinning: pinnedColumns ?? {
4556
4620
  left: enableRowSelection ? ["select"] : [],
4557
4621
  right: actions ? ["actions"] : []
4558
4622
  }
4559
- },
4623
+ }), [
4624
+ initialSorting,
4625
+ pinnedColumns,
4626
+ enableRowSelection,
4627
+ actions
4628
+ ]),
4560
4629
  shallow: false,
4561
4630
  clearOnDefault: true
4562
4631
  });
@@ -4597,7 +4666,7 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
4597
4666
  })
4598
4667
  })
4599
4668
  })] }) : null;
4600
- const renderFilters = () => {
4669
+ const filtersContent = (0, react.useMemo)(() => {
4601
4670
  switch (currentMode) {
4602
4671
  case "simple": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoTableSimpleFilters, {
4603
4672
  table,
@@ -4617,7 +4686,13 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
4617
4686
  align: "start"
4618
4687
  });
4619
4688
  }
4620
- };
4689
+ }, [
4690
+ currentMode,
4691
+ table,
4692
+ shallow,
4693
+ debounceMs,
4694
+ throttleMs
4695
+ ]);
4621
4696
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4622
4697
  className: "space-y-4",
4623
4698
  children: [
@@ -4629,7 +4704,7 @@ function AutoTable({ schema, data, pageCount = 1, overrides, enableRowSelection
4629
4704
  children: [currentMode !== "simple" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableSortList, {
4630
4705
  table,
4631
4706
  align: "start"
4632
- }), renderFilters()]
4707
+ }), filtersContent]
4633
4708
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4634
4709
  className: "flex items-center gap-2",
4635
4710
  children: [
@@ -5218,26 +5293,51 @@ function ImportDialog({ open, onOpenChange, onImport, columns = [], title = "导
5218
5293
  function buildTableOverrides(fields, legacyOverrides) {
5219
5294
  const result = { ...legacyOverrides };
5220
5295
  if (fields) for (const [key, config] of Object.entries(fields)) {
5296
+ const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
5221
5297
  let filterMeta;
5222
- if (config.filter && config.filter.enabled !== false && !config.filter.hidden) {
5223
- const { enabled: _, hidden: __,...filterProps } = config.filter;
5224
- if (Object.keys(filterProps).length > 0) filterMeta = filterProps;
5298
+ if (config.filter && typeof config.filter === "object") {
5299
+ if (config.filter.enabled !== false && config.filter.hidden !== true) {
5300
+ const { enabled: _, hidden: __,...filterProps } = config.filter;
5301
+ if (Object.keys(filterProps).length > 0) filterMeta = filterProps;
5302
+ }
5303
+ }
5304
+ if (config.filter === false) result[key] = {
5305
+ ...result[key],
5306
+ enableColumnFilter: false
5307
+ };
5308
+ else if (config.filter && typeof config.filter === "object") {
5309
+ if (config.filter.enabled === false || config.filter.hidden === true) result[key] = {
5310
+ ...result[key],
5311
+ enableColumnFilter: false
5312
+ };
5225
5313
  }
5226
- result[key] = {
5314
+ if (tableMeta || filterMeta) result[key] = {
5227
5315
  ...result[key],
5228
- ...config.label && { label: config.label },
5229
- ...config.hidden && { hidden: true },
5230
- ...config.table,
5231
- ...filterMeta && { meta: {
5316
+ meta: {
5232
5317
  ...result[key]?.meta ?? {},
5233
- ...config.table?.meta ?? {},
5234
- ...filterMeta
5235
- } }
5318
+ ...tableMeta ?? {},
5319
+ ...filterMeta ?? {}
5320
+ }
5236
5321
  };
5237
- if (config.filter?.enabled === false || config.filter?.hidden === true) result[key] = {
5322
+ if (config.label) result[key] = {
5238
5323
  ...result[key],
5239
- enableColumnFilter: false
5324
+ label: config.label
5325
+ };
5326
+ if (config.hidden) result[key] = {
5327
+ ...result[key],
5328
+ hidden: true
5329
+ };
5330
+ if (config.table === false) result[key] = {
5331
+ ...result[key],
5332
+ hidden: true
5240
5333
  };
5334
+ else if (config.table && typeof config.table === "object") {
5335
+ const { meta,...tableProps } = config.table;
5336
+ result[key] = {
5337
+ ...result[key],
5338
+ ...tableProps
5339
+ };
5340
+ }
5241
5341
  }
5242
5342
  return result;
5243
5343
  }
@@ -5251,12 +5351,24 @@ function buildFormOverrides(fields, legacyOverrides, denyFields) {
5251
5351
  ...result[field],
5252
5352
  "x-hidden": true
5253
5353
  };
5254
- if (fields) for (const [key, config] of Object.entries(fields)) result[key] = {
5255
- ...result[key],
5256
- ...config.label && { title: config.label },
5257
- ...config.hidden && { "x-hidden": true },
5258
- ...config.form
5259
- };
5354
+ if (fields) for (const [key, config] of Object.entries(fields)) {
5355
+ if (config.label) result[key] = {
5356
+ ...result[key],
5357
+ title: config.label
5358
+ };
5359
+ if (config.hidden) result[key] = {
5360
+ ...result[key],
5361
+ "x-hidden": true
5362
+ };
5363
+ if (config.form === false) result[key] = {
5364
+ ...result[key],
5365
+ "x-hidden": true
5366
+ };
5367
+ else if (config.form && typeof config.form === "object") result[key] = {
5368
+ ...result[key],
5369
+ ...config.form
5370
+ };
5371
+ }
5260
5372
  return result;
5261
5373
  }
5262
5374
  /**
@@ -5265,7 +5377,9 @@ function buildFormOverrides(fields, legacyOverrides, denyFields) {
5265
5377
  function buildHiddenColumns(fields, legacyHidden, denyFields) {
5266
5378
  const hidden = new Set([...legacyHidden ?? [], ...denyFields ?? []]);
5267
5379
  if (fields) {
5268
- for (const [key, config] of Object.entries(fields)) if (config.hidden || config.table?.hidden) hidden.add(key);
5380
+ for (const [key, config] of Object.entries(fields)) if (config.hidden) hidden.add(key);
5381
+ else if (config.table === false) hidden.add(key);
5382
+ else if (config.table && typeof config.table === "object" && config.table.hidden) hidden.add(key);
5269
5383
  }
5270
5384
  return Array.from(hidden);
5271
5385
  }
@@ -5431,10 +5545,22 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
5431
5545
  setExporting(false);
5432
5546
  }
5433
5547
  }, [selectedCount, handleExport]);
5434
- const tableOverrides = buildTableOverrides(fields, tableConfig?.overrides);
5435
- const formOverrides = buildFormOverrides(fields, formConfig?.overrides, denyFields);
5436
- const hiddenColumns = buildHiddenColumns(fields, tableConfig?.hidden, denyFields);
5437
- const batchFields = buildBatchUpdateFields(schema, tableConfig?.batchFields, fields);
5548
+ const tableOverrides = react.useMemo(() => buildTableOverrides(fields, tableConfig?.overrides), [fields, tableConfig?.overrides]);
5549
+ const formOverrides = react.useMemo(() => buildFormOverrides(fields, formConfig?.overrides, denyFields), [
5550
+ fields,
5551
+ formConfig?.overrides,
5552
+ denyFields
5553
+ ]);
5554
+ const hiddenColumns = react.useMemo(() => buildHiddenColumns(fields, tableConfig?.hidden, denyFields), [
5555
+ fields,
5556
+ tableConfig?.hidden,
5557
+ denyFields
5558
+ ]);
5559
+ const batchFields = react.useMemo(() => buildBatchUpdateFields(schema, tableConfig?.batchFields, fields), [
5560
+ schema,
5561
+ tableConfig?.batchFields,
5562
+ fields
5563
+ ]);
5438
5564
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5439
5565
  className: "space-y-4",
5440
5566
  children: [
@@ -6166,6 +6292,8 @@ function DataTableToolbarFilter({ column }) {
6166
6292
  const columnMeta = column.columnDef.meta;
6167
6293
  return react.useCallback(() => {
6168
6294
  if (!columnMeta?.variant) return null;
6295
+ const modes = columnMeta.modes;
6296
+ if (modes && !modes.includes("advanced")) return null;
6169
6297
  switch (columnMeta.variant) {
6170
6298
  case "text": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn.Input, {
6171
6299
  placeholder: columnMeta.placeholder ?? columnMeta.label,
@@ -6287,6 +6415,10 @@ function modalReducer(state, action) {
6287
6415
  function useAutoCrudResource({ router, schema, query: queryTransform, options = {} }) {
6288
6416
  const { idKey = "id", defaultVariant = "dialog", hooks, toast: toastAdapter, exportFetcher } = options;
6289
6417
  const toast = (0, react.useMemo)(() => toastAdapter === false ? noopToastAdapter : toastAdapter ?? defaultToastAdapter, [toastAdapter]);
6418
+ const hooksRef = (0, react.useRef)(hooks);
6419
+ (0, react.useEffect)(() => {
6420
+ hooksRef.current = hooks;
6421
+ }, [hooks]);
6290
6422
  const columns = (0, react.useMemo)(() => createTableSchema(schema), [schema]);
6291
6423
  const [urlParams] = useQueryStates({
6292
6424
  page: parseAsInteger.withDefault(1),
@@ -6350,15 +6482,16 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
6350
6482
  payload: variant
6351
6483
  }), []);
6352
6484
  const submitCreate = (0, react.useCallback)(async (values) => {
6485
+ const currentHooks = hooksRef.current;
6353
6486
  try {
6354
- if (hooks?.beforeCreate) {
6355
- const result = await hooks.beforeCreate(values);
6487
+ if (currentHooks?.beforeCreate) {
6488
+ const result = await currentHooks.beforeCreate(values);
6356
6489
  if (typeof result === "boolean") {
6357
6490
  if (result) {
6358
6491
  toast.success("创建成功");
6359
6492
  closeModals();
6360
6493
  listQuery.refetch();
6361
- hooks?.onSuccess?.("create", values);
6494
+ currentHooks?.onSuccess?.("create", values);
6362
6495
  }
6363
6496
  return;
6364
6497
  }
@@ -6369,36 +6502,36 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
6369
6502
  toast.success("创建成功");
6370
6503
  closeModals();
6371
6504
  listQuery.refetch();
6372
- hooks?.onSuccess?.("create", data);
6505
+ currentHooks?.onSuccess?.("create", data);
6373
6506
  },
6374
6507
  onError: (error) => {
6375
6508
  const err = error;
6376
6509
  toast.error(`创建失败: ${err.message}`);
6377
- hooks?.onError?.("create", err);
6510
+ currentHooks?.onError?.("create", err);
6378
6511
  }
6379
6512
  });
6380
6513
  } catch (error) {
6381
6514
  const err = error;
6382
6515
  toast.error(`创建失败: ${err.message}`);
6383
- hooks?.onError?.("create", err);
6516
+ currentHooks?.onError?.("create", err);
6384
6517
  }
6385
6518
  }, [
6386
6519
  createMutation,
6387
6520
  closeModals,
6388
- listQuery,
6389
- hooks
6521
+ listQuery
6390
6522
  ]);
6391
6523
  const submitUpdate = (0, react.useCallback)(async (values) => {
6524
+ const currentHooks = hooksRef.current;
6392
6525
  if (!modal.selected) return;
6393
6526
  try {
6394
- if (hooks?.beforeUpdate) {
6395
- const result = await hooks.beforeUpdate(values, modal.selected);
6527
+ if (currentHooks?.beforeUpdate) {
6528
+ const result = await currentHooks.beforeUpdate(values, modal.selected);
6396
6529
  if (typeof result === "boolean") {
6397
6530
  if (result) {
6398
6531
  toast.success("更新成功");
6399
6532
  closeModals();
6400
6533
  listQuery.refetch();
6401
- hooks?.onSuccess?.("update", values);
6534
+ currentHooks?.onSuccess?.("update", values);
6402
6535
  }
6403
6536
  return;
6404
6537
  }
@@ -6413,38 +6546,38 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
6413
6546
  toast.success("更新成功");
6414
6547
  closeModals();
6415
6548
  listQuery.refetch();
6416
- hooks?.onSuccess?.("update", data);
6549
+ currentHooks?.onSuccess?.("update", data);
6417
6550
  },
6418
6551
  onError: (error) => {
6419
6552
  const err = error;
6420
6553
  toast.error(`更新失败: ${err.message}`);
6421
- hooks?.onError?.("update", err);
6554
+ currentHooks?.onError?.("update", err);
6422
6555
  }
6423
6556
  });
6424
6557
  } catch (error) {
6425
6558
  const err = error;
6426
6559
  toast.error(`更新失败: ${err.message}`);
6427
- hooks?.onError?.("update", err);
6560
+ currentHooks?.onError?.("update", err);
6428
6561
  }
6429
6562
  }, [
6430
6563
  modal.selected,
6431
6564
  idKey,
6432
6565
  updateMutation,
6433
6566
  closeModals,
6434
- listQuery,
6435
- hooks
6567
+ listQuery
6436
6568
  ]);
6437
6569
  const confirmDelete = (0, react.useCallback)(async () => {
6570
+ const currentHooks = hooksRef.current;
6438
6571
  if (!modal.selected) return;
6439
6572
  try {
6440
- if (hooks?.beforeDelete) {
6441
- const result = await hooks.beforeDelete(modal.selected);
6573
+ if (currentHooks?.beforeDelete) {
6574
+ const result = await currentHooks.beforeDelete(modal.selected);
6442
6575
  if (typeof result === "boolean") {
6443
6576
  if (result) {
6444
6577
  toast.success("删除成功");
6445
6578
  closeModals();
6446
6579
  listQuery.refetch();
6447
- hooks?.onSuccess?.("delete", modal.selected);
6580
+ currentHooks?.onSuccess?.("delete", modal.selected);
6448
6581
  }
6449
6582
  return;
6450
6583
  }
@@ -6455,28 +6588,28 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
6455
6588
  toast.success("删除成功");
6456
6589
  closeModals();
6457
6590
  listQuery.refetch();
6458
- hooks?.onSuccess?.("delete", data);
6591
+ currentHooks?.onSuccess?.("delete", data);
6459
6592
  },
6460
6593
  onError: (error) => {
6461
6594
  const err = error;
6462
6595
  toast.error(`删除失败: ${err.message}`);
6463
- hooks?.onError?.("delete", err);
6596
+ currentHooks?.onError?.("delete", err);
6464
6597
  }
6465
6598
  });
6466
6599
  } catch (error) {
6467
6600
  const err = error;
6468
6601
  toast.error(`删除失败: ${err.message}`);
6469
- hooks?.onError?.("delete", err);
6602
+ currentHooks?.onError?.("delete", err);
6470
6603
  }
6471
6604
  }, [
6472
6605
  modal.selected,
6473
6606
  idKey,
6474
6607
  deleteMutation,
6475
6608
  closeModals,
6476
- listQuery,
6477
- hooks
6609
+ listQuery
6478
6610
  ]);
6479
6611
  const deleteMany = (0, react.useCallback)((rows) => {
6612
+ const currentHooks = hooksRef.current;
6480
6613
  if (!deleteManyMutation) {
6481
6614
  toast.error("批量删除功能未启用");
6482
6615
  return;
@@ -6486,21 +6619,21 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
6486
6619
  onSuccess: (data) => {
6487
6620
  toast.success(`成功删除 ${ids.length} 条记录`);
6488
6621
  listQuery.refetch();
6489
- hooks?.onSuccess?.("delete", data);
6622
+ currentHooks?.onSuccess?.("delete", data);
6490
6623
  },
6491
6624
  onError: (error) => {
6492
6625
  const err = error;
6493
6626
  toast.error(`批量删除失败: ${err.message}`);
6494
- hooks?.onError?.("delete", err);
6627
+ currentHooks?.onError?.("delete", err);
6495
6628
  }
6496
6629
  });
6497
6630
  }, [
6498
6631
  deleteManyMutation,
6499
6632
  idKey,
6500
- listQuery,
6501
- hooks
6633
+ listQuery
6502
6634
  ]);
6503
6635
  const updateMany = (0, react.useCallback)((rows, data) => {
6636
+ const currentHooks = hooksRef.current;
6504
6637
  if (!updateManyMutation) {
6505
6638
  toast.error("批量更新功能未启用");
6506
6639
  return;
@@ -6513,19 +6646,18 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
6513
6646
  onSuccess: (result) => {
6514
6647
  toast.success(`成功更新 ${ids.length} 条记录`);
6515
6648
  listQuery.refetch();
6516
- hooks?.onSuccess?.("update", result);
6649
+ currentHooks?.onSuccess?.("update", result);
6517
6650
  },
6518
6651
  onError: (error) => {
6519
6652
  const err = error;
6520
6653
  toast.error(`批量更新失败: ${err.message}`);
6521
- hooks?.onError?.("update", err);
6654
+ currentHooks?.onError?.("update", err);
6522
6655
  }
6523
6656
  });
6524
6657
  }, [
6525
6658
  updateManyMutation,
6526
6659
  idKey,
6527
- listQuery,
6528
- hooks
6660
+ listQuery
6529
6661
  ]);
6530
6662
  const copyRow = (0, react.useCallback)((row) => {
6531
6663
  dispatch({