@wordrhyme/auto-crud 1.12.0 → 1.12.2

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.
Files changed (3) hide show
  1. package/dist/index.cjs +101 -36
  2. package/dist/index.js +101 -36
  3. package/package.json +4 -4
package/dist/index.cjs CHANGED
@@ -4172,6 +4172,14 @@ function inferFilterVariantByFieldName(fieldName) {
4172
4172
  //#region src/lib/schema-bridge/zod-to-columns.tsx
4173
4173
  const parsedFieldCache = /* @__PURE__ */ new WeakMap();
4174
4174
  const baseTableSchemaCache = /* @__PURE__ */ new WeakMap();
4175
+ /** Cache generated value cells; custom cells keep observing every table state update. */
4176
+ function memoCell(render) {
4177
+ const ValueCell = react.memo(function ValueCell$1(context) {
4178
+ useDateFormatterVersion();
4179
+ return render(context);
4180
+ });
4181
+ return (context) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueCell, { ...context });
4182
+ }
4175
4183
  /**
4176
4184
  * 解析 Zod 字段类型
4177
4185
  */
@@ -4392,7 +4400,7 @@ function createTableSchema(schema, options) {
4392
4400
  column,
4393
4401
  label
4394
4402
  }),
4395
- cell: ({ row }) => renderCell(row.getValue(key), parsed.type, meta.options),
4403
+ cell: memoCell(({ row }) => renderCell(row.getValue(key), parsed.type, meta.options)),
4396
4404
  enableColumnFilter: true,
4397
4405
  enableSorting: true,
4398
4406
  meta,
@@ -5388,6 +5396,37 @@ function AutoTable({ schema, data, getRowId, expandedRow, defaultExpanded = fals
5388
5396
  debounceMs,
5389
5397
  throttleMs
5390
5398
  ]);
5399
+ const state = table.getState();
5400
+ const tableContent = (0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, {
5401
+ pagination,
5402
+ table,
5403
+ classNames,
5404
+ expandedRow
5405
+ }), [
5406
+ table,
5407
+ data,
5408
+ columns,
5409
+ getRowId,
5410
+ pageCount,
5411
+ total,
5412
+ stableInitialState,
5413
+ pagination,
5414
+ classNames,
5415
+ expandedRow,
5416
+ state.columnFilters,
5417
+ state.columnOrder,
5418
+ state.columnPinning,
5419
+ state.columnSizing,
5420
+ state.columnSizingInfo,
5421
+ state.columnVisibility,
5422
+ state.expanded,
5423
+ state.globalFilter,
5424
+ state.grouping,
5425
+ state.pagination,
5426
+ state.rowPinning,
5427
+ state.rowSelection,
5428
+ state.sorting
5429
+ ]);
5391
5430
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5392
5431
  className: "space-y-4",
5393
5432
  children: [
@@ -5415,12 +5454,7 @@ function AutoTable({ schema, data, getRowId, expandedRow, defaultExpanded = fals
5415
5454
  ]
5416
5455
  })]
5417
5456
  }),
5418
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, {
5419
- pagination,
5420
- table,
5421
- classNames,
5422
- expandedRow
5423
- }),
5457
+ tableContent,
5424
5458
  enableRowSelection && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoTableActionBar, {
5425
5459
  table,
5426
5460
  onDeleteSelected,
@@ -7167,7 +7201,7 @@ function useDynamicFilterOptions(fields) {
7167
7201
  react.useEffect(() => () => {
7168
7202
  for (const field of Object.keys(controllersRef.current)) clearFieldRequest(field);
7169
7203
  }, [clearFieldRequest]);
7170
- return {
7204
+ return react.useMemo(() => ({
7171
7205
  hasMoreByField,
7172
7206
  labelOptionsByField,
7173
7207
  loadingByField,
@@ -7177,7 +7211,17 @@ function useDynamicFilterOptions(fields) {
7177
7211
  searchableByField,
7178
7212
  loadMore: (field) => loadFieldOptions(field, true),
7179
7213
  setSearchValue
7180
- };
7214
+ }), [
7215
+ hasMoreByField,
7216
+ labelOptionsByField,
7217
+ loadingByField,
7218
+ optionsByField,
7219
+ registeredByField,
7220
+ searchValues,
7221
+ searchableByField,
7222
+ loadFieldOptions,
7223
+ setSearchValue
7224
+ ]);
7181
7225
  }
7182
7226
  function rowHasResolveValue(row, field, value) {
7183
7227
  const rowValue = row[field];
@@ -7288,15 +7332,22 @@ function useDynamicResolveOptions(fields, rows, hiddenColumns) {
7288
7332
  rows,
7289
7333
  sourceEntries
7290
7334
  ]);
7291
- const displayOptionsByField = { ...optionsByField };
7292
- for (const field of Object.keys(fields ?? {}).filter((key) => !hiddenColumns.includes(key))) {
7293
- const projectedOptions = rows.flatMap((row) => {
7294
- const option = readCrudReferenceOption(row, field, row[field]);
7295
- return option ? [option] : [];
7296
- });
7297
- if (projectedOptions.length > 0) displayOptionsByField[field] = mergeFilterOptions(projectedOptions, optionsByField[field] ?? []);
7298
- }
7299
- return { optionsByField: displayOptionsByField };
7335
+ return react.useMemo(() => {
7336
+ const displayOptionsByField = { ...optionsByField };
7337
+ for (const field of Object.keys(fields ?? {}).filter((key) => !hiddenColumns.includes(key))) {
7338
+ const projectedOptions = rows.flatMap((row) => {
7339
+ const option = readCrudReferenceOption(row, field, row[field]);
7340
+ return option ? [option] : [];
7341
+ });
7342
+ if (projectedOptions.length > 0) displayOptionsByField[field] = mergeFilterOptions(projectedOptions, optionsByField[field] ?? []);
7343
+ }
7344
+ return { optionsByField: displayOptionsByField };
7345
+ }, [
7346
+ optionsByField,
7347
+ fields,
7348
+ hiddenColumns,
7349
+ rows
7350
+ ]);
7300
7351
  }
7301
7352
  function getOptionLabel(value, options) {
7302
7353
  const stringValue = String(value);
@@ -7404,7 +7455,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
7404
7455
  const options = tableConfig?.dataSource ? mergeFieldOptions(dynamicResolveOptions, presentationOptions) : presentationOptions ?? mergedSharedDynamicOptions;
7405
7456
  result[key] = {
7406
7457
  ...result[key],
7407
- cell: ({ row, getValue }) => {
7458
+ cell: memoCell(({ row, getValue }) => {
7408
7459
  const value = getValue();
7409
7460
  return config.format?.(value, {
7410
7461
  row: row.original,
@@ -7413,7 +7464,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
7413
7464
  true: "true",
7414
7465
  false: "false"
7415
7466
  }, options, display ?? "auto");
7416
- }
7467
+ })
7417
7468
  };
7418
7469
  }
7419
7470
  }
@@ -7742,10 +7793,14 @@ function resolveActions(actions, defaults, rowActionsLocale, context) {
7742
7793
  * 高级 CRUD 表格组件,封装了完整的增删改查流程
7743
7794
  */
7744
7795
  function AutoCrudTable({ id, title, description, schema, resource, fields, table: tableConfig, form: formConfig, view: viewConfig, permissions, actions: actionItems, toolbar, toolbarActions, locale: localeProp, onCreate, onExport }) {
7745
- const locale = resolveLocale(localeProp);
7796
+ const locale = react.useMemo(() => resolveLocale(localeProp), [localeProp]);
7746
7797
  const getPagination = react.useCallback(() => id ? tablePagination.get(id) : void 0, [id]);
7747
7798
  const registeredPagination = react.useSyncExternalStore(tablePagination.subscribe, getPagination, getPagination);
7748
7799
  const pagination = tableConfig?.pagination ?? registeredPagination;
7800
+ const paginationOptions = react.useMemo(() => pagination ? {
7801
+ pageJumpLabel: locale.pagination?.pageJump,
7802
+ ...pagination
7803
+ } : void 0, [pagination, locale.pagination?.pageJump]);
7749
7804
  const resolvedSchema = resource.schema ?? schema;
7750
7805
  const resolvedFields = react.useMemo(() => applyResourceTablePresentation(mergeFields(resource.fields, fields), resource.fields) ?? {}, [fields, resource.fields]);
7751
7806
  const can = {
@@ -7777,6 +7832,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
7777
7832
  denyFields,
7778
7833
  tableConfig?.overrides
7779
7834
  ]);
7835
+ const excludedColumns = react.useMemo(() => hiddenColumns.filter((key) => !filterOnly.includes(key)), [hiddenColumns, filterOnly]);
7780
7836
  const dynamicResolveOptions = useDynamicResolveOptions(resolvedFields, resource.tableData.data, hiddenColumns);
7781
7837
  const resourceIdKey = resource.idKey ?? "id";
7782
7838
  const actionRegistryVersion = useCrudActionsVersion();
@@ -7968,13 +8024,13 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
7968
8024
  const { type } = parseZodField(resolvedSchema.shape[key]);
7969
8025
  formattedOverrides[key] = {
7970
8026
  ...override,
7971
- cell: (context) => {
8027
+ cell: memoCell((context) => {
7972
8028
  const value = context.getValue();
7973
8029
  return config.format?.(value, {
7974
8030
  row: context.row.original,
7975
8031
  target: "display"
7976
8032
  }) ?? renderCell(value, type, context.column.columnDef.meta?.options);
7977
- }
8033
+ })
7978
8034
  };
7979
8035
  }
7980
8036
  }
@@ -8136,17 +8192,14 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
8136
8192
  data: resource.tableData.data,
8137
8193
  schema: resolvedSchema,
8138
8194
  pageCount: resource.tableData.pageCount,
8139
- pagination: pagination ? {
8140
- pageJumpLabel: locale.pagination?.pageJump,
8141
- ...pagination
8142
- } : void 0,
8195
+ pagination: paginationOptions,
8143
8196
  ...resource.tableData.total !== void 0 ? { total: resource.tableData.total } : {},
8144
8197
  getRowId: tableConfig?.getRowId,
8145
8198
  expandedRow: tableConfig?.expandedRow,
8146
8199
  defaultExpanded: tableConfig?.defaultExpanded,
8147
8200
  overrides: tableOverrides,
8148
8201
  classNames: tableConfig?.classNames,
8149
- exclude: hiddenColumns.filter((key) => !filterOnly.includes(key)),
8202
+ exclude: excludedColumns,
8150
8203
  filterOnly,
8151
8204
  filterMode: tableConfig?.filterModes,
8152
8205
  search: searchConfig,
@@ -8990,7 +9043,8 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
8990
9043
  (0, react.useEffect)(() => {
8991
9044
  hooksRef.current = hooks;
8992
9045
  }, [hooks]);
8993
- const metadata = (router.meta?.useQuery(void 0, { staleTime: 3e4 }))?.data;
9046
+ const metadataQuery = router.meta?.useQuery(void 0, { staleTime: 3e4 });
9047
+ const metadata = metadataQuery?.data;
8994
9048
  const resolvedSchema = (0, react.useMemo)(() => mergeMetadataSchema(schema, metadata?.schema), [schema, metadata?.schema]);
8995
9049
  const defaultSorting = (0, react.useMemo)(() => defaultSortOption === false ? [] : defaultSortOption ?? getDefaultSortingForSchema(resolvedSchema), [defaultSortOption, resolvedSchema]);
8996
9050
  const metadataFields = (0, react.useMemo)(() => readMetadataFields(metadata?.fields), [metadata?.fields]);
@@ -9011,6 +9065,10 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
9011
9065
  search: parseAsString.withDefault("")
9012
9066
  }, { shallow: false });
9013
9067
  const [filters] = useReadableFilters(columns, { shallow: false });
9068
+ const metadataPending = Boolean(metadataQuery?.isPending);
9069
+ const [filtersReady, setFiltersReady] = (0, react.useState)(!metadataPending);
9070
+ (0, react.useEffect)(() => setFiltersReady(!metadataPending), [metadataPending]);
9071
+ const listReady = !metadataPending && filtersReady;
9014
9072
  const queryInput = (0, react.useMemo)(() => {
9015
9073
  const autoParams = {
9016
9074
  page: urlParams.page,
@@ -9026,11 +9084,17 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
9026
9084
  filters,
9027
9085
  queryTransform
9028
9086
  ]);
9087
+ const hasReadyListData = (0, react.useRef)(false);
9029
9088
  const listQuery = router.list.useQuery(queryInput, {
9030
- placeholderData: __tanstack_react_query.keepPreviousData,
9089
+ enabled: listReady,
9090
+ placeholderData: hasReadyListData.current ? __tanstack_react_query.keepPreviousData : void 0,
9031
9091
  staleTime: 0
9032
9092
  });
9033
- const tableRows = listQuery.data?.data ?? [];
9093
+ (0, react.useEffect)(() => {
9094
+ if (listReady && listQuery.data !== void 0) hasReadyListData.current = true;
9095
+ }, [listReady, listQuery.data]);
9096
+ const listData = listReady ? listQuery.data : void 0;
9097
+ const tableRows = listData?.data ?? [];
9034
9098
  const createMutation = router.create.useMutation();
9035
9099
  const updateMutation = router.update.useMutation();
9036
9100
  const deleteMutation = router.delete.useMutation();
@@ -9288,16 +9352,17 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
9288
9352
  ]);
9289
9353
  const canExport = !!(exportFetcher || exportQuery);
9290
9354
  const refresh = (0, react.useCallback)(async () => {
9355
+ if (!listReady) return;
9291
9356
  return listQuery.refetch();
9292
- }, [listQuery]);
9357
+ }, [listQuery, listReady]);
9293
9358
  return {
9294
9359
  idKey,
9295
9360
  tableData: {
9296
9361
  data: tableRows,
9297
- pageCount: listQuery.data?.pageCount ?? 0,
9298
- ...typeof listQuery.data?.total === "number" ? { total: listQuery.data.total } : {},
9299
- isLoading: listQuery.isLoading,
9300
- isFetching: listQuery.isFetching
9362
+ pageCount: listData?.pageCount ?? 0,
9363
+ ...typeof listData?.total === "number" ? { total: listData.total } : {},
9364
+ isLoading: !listReady || listQuery.isLoading,
9365
+ isFetching: !listReady || listQuery.isFetching
9301
9366
  },
9302
9367
  schema: resolvedSchema,
9303
9368
  fields: metadataFields,
package/dist/index.js CHANGED
@@ -4157,6 +4157,14 @@ function inferFilterVariantByFieldName(fieldName) {
4157
4157
  //#region src/lib/schema-bridge/zod-to-columns.tsx
4158
4158
  const parsedFieldCache = /* @__PURE__ */ new WeakMap();
4159
4159
  const baseTableSchemaCache = /* @__PURE__ */ new WeakMap();
4160
+ /** Cache generated value cells; custom cells keep observing every table state update. */
4161
+ function memoCell(render) {
4162
+ const ValueCell = React.memo(function ValueCell$1(context) {
4163
+ useDateFormatterVersion();
4164
+ return render(context);
4165
+ });
4166
+ return (context) => /* @__PURE__ */ jsx(ValueCell, { ...context });
4167
+ }
4160
4168
  /**
4161
4169
  * 解析 Zod 字段类型
4162
4170
  */
@@ -4377,7 +4385,7 @@ function createTableSchema(schema, options) {
4377
4385
  column,
4378
4386
  label
4379
4387
  }),
4380
- cell: ({ row }) => renderCell(row.getValue(key), parsed.type, meta.options),
4388
+ cell: memoCell(({ row }) => renderCell(row.getValue(key), parsed.type, meta.options)),
4381
4389
  enableColumnFilter: true,
4382
4390
  enableSorting: true,
4383
4391
  meta,
@@ -5373,6 +5381,37 @@ function AutoTable({ schema, data, getRowId, expandedRow, defaultExpanded = fals
5373
5381
  debounceMs,
5374
5382
  throttleMs
5375
5383
  ]);
5384
+ const state = table.getState();
5385
+ const tableContent = useMemo(() => /* @__PURE__ */ jsx(DataTable, {
5386
+ pagination,
5387
+ table,
5388
+ classNames,
5389
+ expandedRow
5390
+ }), [
5391
+ table,
5392
+ data,
5393
+ columns,
5394
+ getRowId,
5395
+ pageCount,
5396
+ total,
5397
+ stableInitialState,
5398
+ pagination,
5399
+ classNames,
5400
+ expandedRow,
5401
+ state.columnFilters,
5402
+ state.columnOrder,
5403
+ state.columnPinning,
5404
+ state.columnSizing,
5405
+ state.columnSizingInfo,
5406
+ state.columnVisibility,
5407
+ state.expanded,
5408
+ state.globalFilter,
5409
+ state.grouping,
5410
+ state.pagination,
5411
+ state.rowPinning,
5412
+ state.rowSelection,
5413
+ state.sorting
5414
+ ]);
5376
5415
  return /* @__PURE__ */ jsxs("div", {
5377
5416
  className: "space-y-4",
5378
5417
  children: [
@@ -5400,12 +5439,7 @@ function AutoTable({ schema, data, getRowId, expandedRow, defaultExpanded = fals
5400
5439
  ]
5401
5440
  })]
5402
5441
  }),
5403
- /* @__PURE__ */ jsx(DataTable, {
5404
- pagination,
5405
- table,
5406
- classNames,
5407
- expandedRow
5408
- }),
5442
+ tableContent,
5409
5443
  enableRowSelection && /* @__PURE__ */ jsx(AutoTableActionBar, {
5410
5444
  table,
5411
5445
  onDeleteSelected,
@@ -7152,7 +7186,7 @@ function useDynamicFilterOptions(fields) {
7152
7186
  React.useEffect(() => () => {
7153
7187
  for (const field of Object.keys(controllersRef.current)) clearFieldRequest(field);
7154
7188
  }, [clearFieldRequest]);
7155
- return {
7189
+ return React.useMemo(() => ({
7156
7190
  hasMoreByField,
7157
7191
  labelOptionsByField,
7158
7192
  loadingByField,
@@ -7162,7 +7196,17 @@ function useDynamicFilterOptions(fields) {
7162
7196
  searchableByField,
7163
7197
  loadMore: (field) => loadFieldOptions(field, true),
7164
7198
  setSearchValue
7165
- };
7199
+ }), [
7200
+ hasMoreByField,
7201
+ labelOptionsByField,
7202
+ loadingByField,
7203
+ optionsByField,
7204
+ registeredByField,
7205
+ searchValues,
7206
+ searchableByField,
7207
+ loadFieldOptions,
7208
+ setSearchValue
7209
+ ]);
7166
7210
  }
7167
7211
  function rowHasResolveValue(row, field, value) {
7168
7212
  const rowValue = row[field];
@@ -7273,15 +7317,22 @@ function useDynamicResolveOptions(fields, rows, hiddenColumns) {
7273
7317
  rows,
7274
7318
  sourceEntries
7275
7319
  ]);
7276
- const displayOptionsByField = { ...optionsByField };
7277
- for (const field of Object.keys(fields ?? {}).filter((key) => !hiddenColumns.includes(key))) {
7278
- const projectedOptions = rows.flatMap((row) => {
7279
- const option = readCrudReferenceOption(row, field, row[field]);
7280
- return option ? [option] : [];
7281
- });
7282
- if (projectedOptions.length > 0) displayOptionsByField[field] = mergeFilterOptions(projectedOptions, optionsByField[field] ?? []);
7283
- }
7284
- return { optionsByField: displayOptionsByField };
7320
+ return React.useMemo(() => {
7321
+ const displayOptionsByField = { ...optionsByField };
7322
+ for (const field of Object.keys(fields ?? {}).filter((key) => !hiddenColumns.includes(key))) {
7323
+ const projectedOptions = rows.flatMap((row) => {
7324
+ const option = readCrudReferenceOption(row, field, row[field]);
7325
+ return option ? [option] : [];
7326
+ });
7327
+ if (projectedOptions.length > 0) displayOptionsByField[field] = mergeFilterOptions(projectedOptions, optionsByField[field] ?? []);
7328
+ }
7329
+ return { optionsByField: displayOptionsByField };
7330
+ }, [
7331
+ optionsByField,
7332
+ fields,
7333
+ hiddenColumns,
7334
+ rows
7335
+ ]);
7285
7336
  }
7286
7337
  function getOptionLabel(value, options) {
7287
7338
  const stringValue = String(value);
@@ -7389,7 +7440,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
7389
7440
  const options = tableConfig?.dataSource ? mergeFieldOptions(dynamicResolveOptions, presentationOptions) : presentationOptions ?? mergedSharedDynamicOptions;
7390
7441
  result[key] = {
7391
7442
  ...result[key],
7392
- cell: ({ row, getValue }) => {
7443
+ cell: memoCell(({ row, getValue }) => {
7393
7444
  const value = getValue();
7394
7445
  return config.format?.(value, {
7395
7446
  row: row.original,
@@ -7398,7 +7449,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
7398
7449
  true: "true",
7399
7450
  false: "false"
7400
7451
  }, options, display ?? "auto");
7401
- }
7452
+ })
7402
7453
  };
7403
7454
  }
7404
7455
  }
@@ -7727,10 +7778,14 @@ function resolveActions(actions, defaults, rowActionsLocale, context) {
7727
7778
  * 高级 CRUD 表格组件,封装了完整的增删改查流程
7728
7779
  */
7729
7780
  function AutoCrudTable({ id, title, description, schema, resource, fields, table: tableConfig, form: formConfig, view: viewConfig, permissions, actions: actionItems, toolbar, toolbarActions, locale: localeProp, onCreate, onExport }) {
7730
- const locale = resolveLocale(localeProp);
7781
+ const locale = React.useMemo(() => resolveLocale(localeProp), [localeProp]);
7731
7782
  const getPagination = React.useCallback(() => id ? tablePagination.get(id) : void 0, [id]);
7732
7783
  const registeredPagination = React.useSyncExternalStore(tablePagination.subscribe, getPagination, getPagination);
7733
7784
  const pagination = tableConfig?.pagination ?? registeredPagination;
7785
+ const paginationOptions = React.useMemo(() => pagination ? {
7786
+ pageJumpLabel: locale.pagination?.pageJump,
7787
+ ...pagination
7788
+ } : void 0, [pagination, locale.pagination?.pageJump]);
7734
7789
  const resolvedSchema = resource.schema ?? schema;
7735
7790
  const resolvedFields = React.useMemo(() => applyResourceTablePresentation(mergeFields(resource.fields, fields), resource.fields) ?? {}, [fields, resource.fields]);
7736
7791
  const can = {
@@ -7762,6 +7817,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
7762
7817
  denyFields,
7763
7818
  tableConfig?.overrides
7764
7819
  ]);
7820
+ const excludedColumns = React.useMemo(() => hiddenColumns.filter((key) => !filterOnly.includes(key)), [hiddenColumns, filterOnly]);
7765
7821
  const dynamicResolveOptions = useDynamicResolveOptions(resolvedFields, resource.tableData.data, hiddenColumns);
7766
7822
  const resourceIdKey = resource.idKey ?? "id";
7767
7823
  const actionRegistryVersion = useCrudActionsVersion();
@@ -7953,13 +8009,13 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
7953
8009
  const { type } = parseZodField(resolvedSchema.shape[key]);
7954
8010
  formattedOverrides[key] = {
7955
8011
  ...override,
7956
- cell: (context) => {
8012
+ cell: memoCell((context) => {
7957
8013
  const value = context.getValue();
7958
8014
  return config.format?.(value, {
7959
8015
  row: context.row.original,
7960
8016
  target: "display"
7961
8017
  }) ?? renderCell(value, type, context.column.columnDef.meta?.options);
7962
- }
8018
+ })
7963
8019
  };
7964
8020
  }
7965
8021
  }
@@ -8121,17 +8177,14 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
8121
8177
  data: resource.tableData.data,
8122
8178
  schema: resolvedSchema,
8123
8179
  pageCount: resource.tableData.pageCount,
8124
- pagination: pagination ? {
8125
- pageJumpLabel: locale.pagination?.pageJump,
8126
- ...pagination
8127
- } : void 0,
8180
+ pagination: paginationOptions,
8128
8181
  ...resource.tableData.total !== void 0 ? { total: resource.tableData.total } : {},
8129
8182
  getRowId: tableConfig?.getRowId,
8130
8183
  expandedRow: tableConfig?.expandedRow,
8131
8184
  defaultExpanded: tableConfig?.defaultExpanded,
8132
8185
  overrides: tableOverrides,
8133
8186
  classNames: tableConfig?.classNames,
8134
- exclude: hiddenColumns.filter((key) => !filterOnly.includes(key)),
8187
+ exclude: excludedColumns,
8135
8188
  filterOnly,
8136
8189
  filterMode: tableConfig?.filterModes,
8137
8190
  search: searchConfig,
@@ -8975,7 +9028,8 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
8975
9028
  useEffect(() => {
8976
9029
  hooksRef.current = hooks;
8977
9030
  }, [hooks]);
8978
- const metadata = (router.meta?.useQuery(void 0, { staleTime: 3e4 }))?.data;
9031
+ const metadataQuery = router.meta?.useQuery(void 0, { staleTime: 3e4 });
9032
+ const metadata = metadataQuery?.data;
8979
9033
  const resolvedSchema = useMemo(() => mergeMetadataSchema(schema, metadata?.schema), [schema, metadata?.schema]);
8980
9034
  const defaultSorting = useMemo(() => defaultSortOption === false ? [] : defaultSortOption ?? getDefaultSortingForSchema(resolvedSchema), [defaultSortOption, resolvedSchema]);
8981
9035
  const metadataFields = useMemo(() => readMetadataFields(metadata?.fields), [metadata?.fields]);
@@ -8996,6 +9050,10 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
8996
9050
  search: parseAsString.withDefault("")
8997
9051
  }, { shallow: false });
8998
9052
  const [filters] = useReadableFilters(columns, { shallow: false });
9053
+ const metadataPending = Boolean(metadataQuery?.isPending);
9054
+ const [filtersReady, setFiltersReady] = useState(!metadataPending);
9055
+ useEffect(() => setFiltersReady(!metadataPending), [metadataPending]);
9056
+ const listReady = !metadataPending && filtersReady;
8999
9057
  const queryInput = useMemo(() => {
9000
9058
  const autoParams = {
9001
9059
  page: urlParams.page,
@@ -9011,11 +9069,17 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
9011
9069
  filters,
9012
9070
  queryTransform
9013
9071
  ]);
9072
+ const hasReadyListData = useRef(false);
9014
9073
  const listQuery = router.list.useQuery(queryInput, {
9015
- placeholderData: keepPreviousData,
9074
+ enabled: listReady,
9075
+ placeholderData: hasReadyListData.current ? keepPreviousData : void 0,
9016
9076
  staleTime: 0
9017
9077
  });
9018
- const tableRows = listQuery.data?.data ?? [];
9078
+ useEffect(() => {
9079
+ if (listReady && listQuery.data !== void 0) hasReadyListData.current = true;
9080
+ }, [listReady, listQuery.data]);
9081
+ const listData = listReady ? listQuery.data : void 0;
9082
+ const tableRows = listData?.data ?? [];
9019
9083
  const createMutation = router.create.useMutation();
9020
9084
  const updateMutation = router.update.useMutation();
9021
9085
  const deleteMutation = router.delete.useMutation();
@@ -9273,16 +9337,17 @@ function useAutoCrudResource({ router, schema, query: queryTransform, fields, op
9273
9337
  ]);
9274
9338
  const canExport = !!(exportFetcher || exportQuery);
9275
9339
  const refresh = useCallback(async () => {
9340
+ if (!listReady) return;
9276
9341
  return listQuery.refetch();
9277
- }, [listQuery]);
9342
+ }, [listQuery, listReady]);
9278
9343
  return {
9279
9344
  idKey,
9280
9345
  tableData: {
9281
9346
  data: tableRows,
9282
- pageCount: listQuery.data?.pageCount ?? 0,
9283
- ...typeof listQuery.data?.total === "number" ? { total: listQuery.data.total } : {},
9284
- isLoading: listQuery.isLoading,
9285
- isFetching: listQuery.isFetching
9347
+ pageCount: listData?.pageCount ?? 0,
9348
+ ...typeof listData?.total === "number" ? { total: listData.total } : {},
9349
+ isLoading: !listReady || listQuery.isLoading,
9350
+ isFetching: !listReady || listQuery.isFetching
9286
9351
  },
9287
9352
  schema: resolvedSchema,
9288
9353
  fields: metadataFields,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wordrhyme/auto-crud",
3
3
  "type": "module",
4
- "version": "1.12.0",
4
+ "version": "1.12.2",
5
5
  "description": "Schema-first CRUD components with auto-generated tables and forms",
6
6
  "author": "wordrhyme",
7
7
  "license": "MIT",
@@ -94,11 +94,11 @@
94
94
  "tsdown": "^0.15.12",
95
95
  "typescript": "^5.9.3",
96
96
  "vitest": "^3.2.4",
97
- "@internal/eslint-config": "0.3.0",
98
97
  "@internal/prettier-config": "0.0.1",
99
- "@internal/tsdown-config": "0.1.0",
100
98
  "@internal/tsconfig": "0.1.0",
101
- "@internal/vitest-config": "0.1.0"
99
+ "@internal/eslint-config": "0.3.0",
100
+ "@internal/vitest-config": "0.1.0",
101
+ "@internal/tsdown-config": "0.1.0"
102
102
  },
103
103
  "prettier": "@internal/prettier-config",
104
104
  "scripts": {