@wordrhyme/auto-crud 1.1.8 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -5235,65 +5235,59 @@ function createEditFormSchema(schema, options) {
5235
5235
  //#endregion
5236
5236
  //#region src/lib/registries.ts
5237
5237
  function createRegistry(label) {
5238
- const items = /* @__PURE__ */ new Map();
5238
+ const entries = /* @__PURE__ */ new Map();
5239
5239
  const listeners = /* @__PURE__ */ new Set();
5240
- let notifyQueued = false;
5241
5240
  const notify = () => {
5242
- if (notifyQueued) return;
5243
- notifyQueued = true;
5244
5241
  queueMicrotask(() => {
5245
- notifyQueued = false;
5246
- listeners.forEach((listener) => listener());
5242
+ for (const listener of listeners) listener();
5247
5243
  });
5248
5244
  };
5249
5245
  return {
5250
5246
  register(name, value) {
5251
- const current = items.get(name);
5252
- if (current === value) return;
5253
- if (current !== void 0) {
5247
+ if (entries.has(name)) {
5254
5248
  console.warn(`[AutoCrud] ${label} "${name}" is already registered.`);
5255
5249
  return;
5256
5250
  }
5257
- items.set(name, value);
5251
+ entries.set(name, value);
5258
5252
  notify();
5259
5253
  },
5260
5254
  unregister(name) {
5261
- if (!items.delete(name)) return;
5255
+ if (!entries.delete(name)) return;
5262
5256
  notify();
5263
5257
  },
5264
5258
  get(name) {
5265
- return items.get(name);
5259
+ return entries.get(name);
5266
5260
  },
5267
5261
  all() {
5268
- return Object.fromEntries(items);
5262
+ return Object.fromEntries(entries);
5269
5263
  },
5270
5264
  subscribe(listener) {
5271
5265
  listeners.add(listener);
5272
- return () => {
5273
- listeners.delete(listener);
5274
- };
5266
+ return () => listeners.delete(listener);
5275
5267
  }
5276
5268
  };
5277
5269
  }
5278
5270
  const formComponents = createRegistry("form component");
5279
5271
  const dataSources = createRegistry("data source");
5280
5272
  function normalizeDataSourceConfig(config) {
5281
- if (!config) return void 0;
5282
- if (typeof config === "string") return {
5273
+ if (typeof config === "string") return config.length > 0 ? {
5283
5274
  key: config,
5284
5275
  dependsOn: [],
5285
5276
  resetOnChange: false
5286
- };
5277
+ } : void 0;
5278
+ if (!config?.key) return void 0;
5287
5279
  return {
5288
5280
  key: config.key,
5289
- dependsOn: config.dependsOn ?? [],
5290
- resetOnChange: config.resetOnChange ?? false
5281
+ dependsOn: Array.isArray(config.dependsOn) ? config.dependsOn : [],
5282
+ resetOnChange: config.resetOnChange === true
5291
5283
  };
5292
5284
  }
5293
5285
  function normalizeOptions(result) {
5294
5286
  const options = Array.isArray(result) ? result : result?.options;
5295
- if (!options) return [];
5296
- return options.map((option) => ({
5287
+ if (!Array.isArray(options)) return [];
5288
+ return options.filter((option) => {
5289
+ return typeof option === "object" && option !== null && typeof option.value === "string" && typeof option.label === "string";
5290
+ }).map((option) => ({
5297
5291
  ...option,
5298
5292
  value: String(option.value)
5299
5293
  }));
@@ -5347,7 +5341,7 @@ const defaultFieldComponents = {
5347
5341
  decorator: "FormItem"
5348
5342
  }
5349
5343
  };
5350
- function useRegistryVersion(subscribe) {
5344
+ function useRegistryVersion$1(subscribe) {
5351
5345
  const [version, setVersion] = (0, react.useState)(0);
5352
5346
  (0, react.useEffect)(() => subscribe(() => setVersion((current) => current + 1)), [subscribe]);
5353
5347
  return version;
@@ -5359,13 +5353,15 @@ function isDataSourceConfig(value) {
5359
5353
  }
5360
5354
  function collectDataSourceConfigs(schema, result = {}) {
5361
5355
  const properties = schema.properties;
5362
- if (!properties) return result;
5356
+ if (!properties || typeof properties !== "object") return result;
5363
5357
  for (const [key, property] of Object.entries(properties)) {
5364
- const customDataSource = property["x-data-source"];
5365
- const schemaDataSource = property.dataSource;
5358
+ if (!property || typeof property !== "object" || Array.isArray(property)) continue;
5359
+ const record = property;
5360
+ const customDataSource = record["x-data-source"];
5361
+ const schemaDataSource = record.dataSource;
5366
5362
  const dataSourceConfig = isDataSourceConfig(customDataSource) ? customDataSource : isDataSourceConfig(schemaDataSource) ? schemaDataSource : void 0;
5367
5363
  if (dataSourceConfig) result[key] = dataSourceConfig;
5368
- collectDataSourceConfigs(property, result);
5364
+ collectDataSourceConfigs(record, result);
5369
5365
  }
5370
5366
  return result;
5371
5367
  }
@@ -5374,7 +5370,7 @@ function useFormDataSources(form, schema) {
5374
5370
  const sourceEntries = Object.entries(collectDataSourceConfigs(schema)).map(([fieldName, config]) => {
5375
5371
  const normalized = normalizeDataSourceConfig(config);
5376
5372
  return normalized ? [fieldName, normalized] : void 0;
5377
- }).filter(Boolean);
5373
+ }).filter((entry) => entry !== void 0);
5378
5374
  if (sourceEntries.length === 0) return;
5379
5375
  let active = true;
5380
5376
  const effectId = Symbol("autoCrudDataSources");
@@ -5410,14 +5406,12 @@ function useFormDataSources(form, schema) {
5410
5406
  };
5411
5407
  for (const [fieldName, source] of sourceEntries) loadFieldOptions(fieldName, source);
5412
5408
  form.addEffects(effectId, () => {
5413
- new Set(sourceEntries.flatMap(([, source]) => source.dependsOn)).forEach((dependency) => {
5414
- (0, __formily_core.onFieldValueChange)(dependency, () => {
5415
- sourceEntries.forEach(([fieldName, source]) => {
5416
- if (!source.dependsOn.includes(dependency)) return;
5417
- if (source.resetOnChange) form.setValuesIn(fieldName, void 0);
5418
- loadFieldOptions(fieldName, source);
5419
- });
5420
- });
5409
+ for (const dependency of new Set(sourceEntries.flatMap(([, source]) => source.dependsOn))) (0, __formily_core.onFieldValueChange)(dependency, () => {
5410
+ for (const [fieldName, source] of sourceEntries) {
5411
+ if (!source.dependsOn.includes(dependency)) continue;
5412
+ if (source.resetOnChange) form.setValuesIn(fieldName, void 0);
5413
+ loadFieldOptions(fieldName, source);
5414
+ }
5421
5415
  });
5422
5416
  });
5423
5417
  return () => {
@@ -5426,9 +5420,9 @@ function useFormDataSources(form, schema) {
5426
5420
  form.removeEffects(effectId);
5427
5421
  };
5428
5422
  }, [
5429
- useRegistryVersion(dataSources.subscribe),
5430
5423
  form,
5431
- schema
5424
+ schema,
5425
+ useRegistryVersion$1(dataSources.subscribe)
5432
5426
  ]);
5433
5427
  }
5434
5428
  function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides, mode = "create", loading = false, gridColumns = 1, labelAlign = "top", labelWidth, showSubmitButton = true }, ref) {
@@ -5449,7 +5443,7 @@ function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides,
5449
5443
  const fieldComponents = (0, react.useMemo)(() => ({ fields: {
5450
5444
  ...defaultFieldComponents,
5451
5445
  ...formComponents.all()
5452
- } }), [useRegistryVersion(formComponents.subscribe)]);
5446
+ } }), [useRegistryVersion$1(formComponents.subscribe)]);
5453
5447
  useFormDataSources(form, formSchema);
5454
5448
  const handleSubmit = async () => {
5455
5449
  await form.validate();
@@ -6307,6 +6301,69 @@ function toBatchOptions(options) {
6307
6301
  value
6308
6302
  }));
6309
6303
  }
6304
+ function getFilterDataSource(config) {
6305
+ if (config.filter && typeof config.filter === "object") return config.filter.dataSource ?? config.dataSource;
6306
+ return config.dataSource;
6307
+ }
6308
+ function shouldLoadDynamicFilterOptions(config) {
6309
+ if (config.filter === false) return false;
6310
+ if (normalizeFieldOptions(config.enum)) return false;
6311
+ if (config.filter && typeof config.filter === "object") {
6312
+ if (config.filter.enabled === false || config.filter.hidden === true) return false;
6313
+ if (normalizeFieldOptions(config.filter.options)) return false;
6314
+ }
6315
+ return normalizeDataSourceConfig(getFilterDataSource(config)) !== void 0;
6316
+ }
6317
+ function useRegistryVersion(subscribe) {
6318
+ const [version, setVersion] = react.useState(0);
6319
+ react.useEffect(() => subscribe(() => setVersion((current) => current + 1)), [subscribe]);
6320
+ return version;
6321
+ }
6322
+ function useDynamicFilterOptions(fields) {
6323
+ const registryVersion = useRegistryVersion(dataSources.subscribe);
6324
+ const [optionsByField, setOptionsByField] = react.useState({});
6325
+ const sourceEntries = react.useMemo(() => {
6326
+ if (!fields) return [];
6327
+ return Object.entries(fields).flatMap(([field, config]) => {
6328
+ if (!shouldLoadDynamicFilterOptions(config)) return [];
6329
+ const source = normalizeDataSourceConfig(getFilterDataSource(config));
6330
+ return source ? [{
6331
+ field,
6332
+ source
6333
+ }] : [];
6334
+ });
6335
+ }, [fields]);
6336
+ react.useEffect(() => {
6337
+ if (sourceEntries.length === 0) {
6338
+ setOptionsByField({});
6339
+ return;
6340
+ }
6341
+ let active = true;
6342
+ const controller = typeof AbortController === "undefined" ? void 0 : new AbortController();
6343
+ Promise.all(sourceEntries.map(async ({ field, source }) => {
6344
+ const loader = dataSources.get(source.key);
6345
+ if (!loader) return [field, []];
6346
+ try {
6347
+ return [field, normalizeOptions(await loader({
6348
+ field,
6349
+ values: {},
6350
+ signal: controller?.signal
6351
+ }))];
6352
+ } catch (error) {
6353
+ if (!controller?.signal.aborted) console.warn(`[AutoCrud] Failed to load filter data source "${source.key}".`, error);
6354
+ return [field, []];
6355
+ }
6356
+ })).then((entries) => {
6357
+ if (!active) return;
6358
+ setOptionsByField(Object.fromEntries(entries));
6359
+ });
6360
+ return () => {
6361
+ active = false;
6362
+ controller?.abort();
6363
+ };
6364
+ }, [sourceEntries, registryVersion]);
6365
+ return optionsByField;
6366
+ }
6310
6367
  function getOptionLabel(value, options) {
6311
6368
  const stringValue = String(value);
6312
6369
  return options?.find((option) => option.value === stringValue)?.label ?? stringValue;
@@ -6315,15 +6372,21 @@ function getOptionLabel(value, options) {
6315
6372
  * 从统一配置生成表格 overrides
6316
6373
  * 当 filter 配置存在时,合并到 meta 中(不影响列隐藏)
6317
6374
  */
6318
- function buildTableOverrides(fields, legacyOverrides) {
6375
+ function buildTableOverrides(fields, legacyOverrides, dynamicFilterOptions) {
6319
6376
  const result = { ...legacyOverrides };
6320
6377
  if (fields) for (const [key, config] of Object.entries(fields)) {
6321
- const tableOptions = toTableOptions(normalizeFieldOptions(config.enum));
6378
+ const fieldOptions = normalizeFieldOptions(config.enum);
6379
+ const tableOptions = toTableOptions(fieldOptions);
6380
+ const dynamicOptions = !fieldOptions ? toTableOptions(normalizeFieldOptions(dynamicFilterOptions?.[key])) : void 0;
6322
6381
  const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
6323
6382
  const fieldEnumMeta = tableOptions ? {
6324
6383
  options: tableOptions,
6325
6384
  variant: "multiSelect"
6326
6385
  } : void 0;
6386
+ const fieldDataSourceMeta = dynamicOptions ? {
6387
+ options: dynamicOptions,
6388
+ variant: "multiSelect"
6389
+ } : void 0;
6327
6390
  let filterMeta;
6328
6391
  if (config.filter && typeof config.filter === "object") {
6329
6392
  if (config.filter.enabled !== false && config.filter.hidden !== true) {
@@ -6341,11 +6404,12 @@ function buildTableOverrides(fields, legacyOverrides) {
6341
6404
  enableColumnFilter: false
6342
6405
  };
6343
6406
  }
6344
- if (fieldEnumMeta || tableMeta || filterMeta) result[key] = {
6407
+ if (fieldEnumMeta || fieldDataSourceMeta || tableMeta || filterMeta) result[key] = {
6345
6408
  ...result[key],
6346
6409
  meta: {
6347
6410
  ...result[key]?.meta ?? {},
6348
6411
  ...fieldEnumMeta ?? {},
6412
+ ...fieldDataSourceMeta ?? {},
6349
6413
  ...tableMeta ?? {},
6350
6414
  ...filterMeta ?? {}
6351
6415
  }
@@ -6658,6 +6722,7 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
6658
6722
  const [selectedCount, setSelectedCount] = react.useState(0);
6659
6723
  const [exporting, setExporting] = react.useState(false);
6660
6724
  const getSelectedRowsRef = react.useRef(null);
6725
+ const dynamicFilterOptions = useDynamicFilterOptions(resolvedFields);
6661
6726
  const importColumns = react.useMemo(() => {
6662
6727
  const shape = resolvedSchema.shape;
6663
6728
  const denySet = new Set(denyFields ?? []);
@@ -6694,7 +6759,11 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
6694
6759
  setExporting(false);
6695
6760
  }
6696
6761
  }, [selectedCount, handleExport]);
6697
- const tableOverrides = react.useMemo(() => buildTableOverrides(resolvedFields, tableConfig?.overrides), [resolvedFields, tableConfig?.overrides]);
6762
+ const tableOverrides = react.useMemo(() => buildTableOverrides(resolvedFields, tableConfig?.overrides, dynamicFilterOptions), [
6763
+ resolvedFields,
6764
+ tableConfig?.overrides,
6765
+ dynamicFilterOptions
6766
+ ]);
6698
6767
  const formOverrides = react.useMemo(() => buildFormOverrides(resolvedFields, formConfig?.overrides, denyFields), [
6699
6768
  resolvedFields,
6700
6769
  formConfig?.overrides,
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_runtime2 from "react/jsx-runtime";
2
2
  import { z } from "zod";
3
3
  import * as _tanstack_react_table0 from "@tanstack/react-table";
4
4
  import { Column, ColumnDef, ColumnSort, Row, RowData, Table, TableOptions, TableState } from "@tanstack/react-table";
@@ -362,7 +362,7 @@ declare function AutoTableActionBar<TData>({
362
362
  enableDelete,
363
363
  extraActions,
364
364
  actions
365
- }: AutoTableActionBarProps<TData>): react_jsx_runtime3.JSX.Element;
365
+ }: AutoTableActionBarProps<TData>): react_jsx_runtime2.JSX.Element;
366
366
  //#endregion
367
367
  //#region src/lib/schema-bridge/types.d.ts
368
368
  /**
@@ -530,7 +530,7 @@ declare function AutoTable<T extends z.ZodObject<z.ZodRawShape>>({
530
530
  showDefaultExport,
531
531
  onSelectedCountChange,
532
532
  getSelectedRows
533
- }: AutoTableProps<T>): react_jsx_runtime3.JSX.Element;
533
+ }: AutoTableProps<T>): react_jsx_runtime2.JSX.Element;
534
534
  //#endregion
535
535
  //#region src/i18n/locale.d.ts
536
536
  /**
@@ -642,11 +642,10 @@ type AutoCrudDataSourceContext = {
642
642
  values?: Record<string, unknown>;
643
643
  signal?: AbortSignal;
644
644
  };
645
- type AutoCrudDataSourceLoader = (context: AutoCrudDataSourceContext) => Promise<AutoCrudOption[] | {
646
- options?: AutoCrudOption[];
647
- }> | AutoCrudOption[] | {
645
+ type AutoCrudDataSourceResult = AutoCrudOption[] | {
648
646
  options?: AutoCrudOption[];
649
647
  };
648
+ type AutoCrudDataSourceLoader = (context: AutoCrudDataSourceContext) => AutoCrudDataSourceResult | Promise<AutoCrudDataSourceResult>;
650
649
  type AutoCrudDataSourceConfig = string | {
651
650
  key: string;
652
651
  dependsOn?: string[];
@@ -672,9 +671,7 @@ declare function normalizeDataSourceConfig(config: AutoCrudDataSourceConfig | un
672
671
  dependsOn: string[];
673
672
  resetOnChange: boolean;
674
673
  } | undefined;
675
- declare function normalizeOptions(result: AutoCrudOption[] | {
676
- options?: AutoCrudOption[];
677
- } | undefined): AutoCrudOption[];
674
+ declare function normalizeOptions(result: AutoCrudDataSourceResult | undefined): AutoCrudOption[];
678
675
  //#endregion
679
676
  //#region src/components/auto-crud/auto-crud-table.d.ts
680
677
  /**
@@ -688,6 +685,8 @@ interface FilterConfig {
688
685
  variant?: 'text' | 'number' | 'range' | 'date' | 'dateRange' | 'boolean' | 'select' | 'multiSelect';
689
686
  /** select/multiSelect 的选项列表 */
690
687
  options?: FieldOption[];
688
+ /** select/multiSelect 的动态选项源 */
689
+ dataSource?: AutoCrudDataSourceConfig;
691
690
  /** range 的最小/最大值 */
692
691
  range?: [number, number];
693
692
  /** number 的单位 */
@@ -936,7 +935,7 @@ declare function AutoCrudTable<TSchema extends z.ZodObject<z.ZodRawShape>>({
936
935
  toolbarActions,
937
936
  locale: localeProp,
938
937
  onCreate
939
- }: AutoCrudTableProps<TSchema>): react_jsx_runtime3.JSX.Element;
938
+ }: AutoCrudTableProps<TSchema>): react_jsx_runtime2.JSX.Element;
940
939
  //#endregion
941
940
  //#region src/components/auto-crud/auto-form.d.ts
942
941
  interface AutoFormProps<T extends z.ZodObject<z.ZodRawShape>> {
@@ -968,7 +967,7 @@ declare function AutoFormInner<T extends z.ZodObject<z.ZodRawShape>>({
968
967
  labelAlign,
969
968
  labelWidth,
970
969
  showSubmitButton
971
- }: AutoFormProps<T>, ref: React.Ref<AutoFormRef>): react_jsx_runtime3.JSX.Element;
970
+ }: AutoFormProps<T>, ref: React.Ref<AutoFormRef>): react_jsx_runtime2.JSX.Element;
972
971
  declare const AutoForm: <T extends z.ZodObject<z.ZodRawShape>>(props: AutoFormProps<T> & {
973
972
  ref?: React.Ref<AutoFormRef>;
974
973
  }) => ReturnType<typeof AutoFormInner>;
@@ -1182,12 +1181,12 @@ declare const filterItemSchema: z.ZodObject<{
1182
1181
  variant: z.ZodEnum<{
1183
1182
  number: "number";
1184
1183
  boolean: "boolean";
1185
- date: "date";
1186
1184
  text: "text";
1185
+ range: "range";
1186
+ date: "date";
1187
+ dateRange: "dateRange";
1187
1188
  select: "select";
1188
1189
  multiSelect: "multiSelect";
1189
- dateRange: "dateRange";
1190
- range: "range";
1191
1190
  }>;
1192
1191
  operator: z.ZodEnum<{
1193
1192
  iLike: "iLike";
@@ -1270,7 +1269,7 @@ declare function AutoTableSimpleFilters<TData>({
1270
1269
  filters: externalFilters,
1271
1270
  onFiltersChange,
1272
1271
  leading
1273
- }: AutoTableSimpleFiltersProps<TData>): react_jsx_runtime3.JSX.Element | null;
1272
+ }: AutoTableSimpleFiltersProps<TData>): react_jsx_runtime2.JSX.Element | null;
1274
1273
  //#endregion
1275
1274
  //#region src/components/auto-crud/form-modal.d.ts
1276
1275
  type ModalVariant = "dialog" | "sheet";
@@ -1312,7 +1311,7 @@ declare function CrudFormModal<T extends z.ZodObject<z.ZodRawShape>>({
1312
1311
  labelAlign,
1313
1312
  labelWidth,
1314
1313
  className
1315
- }: CrudFormModalProps<T>): react_jsx_runtime3.JSX.Element;
1314
+ }: CrudFormModalProps<T>): react_jsx_runtime2.JSX.Element;
1316
1315
  //#endregion
1317
1316
  //#region src/components/auto-crud/import-dialog.d.ts
1318
1317
  interface ImportDialogProps {
@@ -1334,7 +1333,7 @@ declare function ImportDialog({
1334
1333
  columns,
1335
1334
  title,
1336
1335
  locale
1337
- }: ImportDialogProps): react_jsx_runtime3.JSX.Element;
1336
+ }: ImportDialogProps): react_jsx_runtime2.JSX.Element;
1338
1337
  //#endregion
1339
1338
  //#region src/components/auto-crud/export-dialog.d.ts
1340
1339
  type ExportMode = "selected" | "filtered";
@@ -1354,7 +1353,7 @@ declare function ExportDialog({
1354
1353
  selectedCount,
1355
1354
  onExport,
1356
1355
  canExportFiltered
1357
- }: ExportDialogProps): react_jsx_runtime3.JSX.Element;
1356
+ }: ExportDialogProps): react_jsx_runtime2.JSX.Element;
1358
1357
  //#endregion
1359
1358
  //#region src/components/data-table/data-table.d.ts
1360
1359
  interface DataTableProps<TData> extends React$1.ComponentProps<"div"> {
@@ -1367,7 +1366,7 @@ declare function DataTable<TData>({
1367
1366
  children,
1368
1367
  className,
1369
1368
  ...props
1370
- }: DataTableProps<TData>): react_jsx_runtime3.JSX.Element;
1369
+ }: DataTableProps<TData>): react_jsx_runtime2.JSX.Element;
1371
1370
  //#endregion
1372
1371
  //#region src/components/data-table/data-table-advanced-toolbar.d.ts
1373
1372
  interface DataTableAdvancedToolbarProps<TData> extends React$1.ComponentProps<"div"> {
@@ -1378,7 +1377,7 @@ declare function DataTableAdvancedToolbar<TData>({
1378
1377
  children,
1379
1378
  className,
1380
1379
  ...props
1381
- }: DataTableAdvancedToolbarProps<TData>): react_jsx_runtime3.JSX.Element;
1380
+ }: DataTableAdvancedToolbarProps<TData>): react_jsx_runtime2.JSX.Element;
1382
1381
  //#endregion
1383
1382
  //#region src/components/data-table/data-table-column-header.d.ts
1384
1383
  interface DataTableColumnHeaderProps<TData, TValue> extends React.ComponentProps<typeof DropdownMenuTrigger> {
@@ -1390,7 +1389,7 @@ declare function DataTableColumnHeader<TData, TValue>({
1390
1389
  label,
1391
1390
  className,
1392
1391
  ...props
1393
- }: DataTableColumnHeaderProps<TData, TValue>): react_jsx_runtime3.JSX.Element;
1392
+ }: DataTableColumnHeaderProps<TData, TValue>): react_jsx_runtime2.JSX.Element;
1394
1393
  //#endregion
1395
1394
  //#region src/components/data-table/data-table-faceted-filter.d.ts
1396
1395
  interface DataTableFacetedFilterProps<TData, TValue> {
@@ -1404,7 +1403,7 @@ declare function DataTableFacetedFilter<TData, TValue>({
1404
1403
  title,
1405
1404
  options,
1406
1405
  multiple
1407
- }: DataTableFacetedFilterProps<TData, TValue>): react_jsx_runtime3.JSX.Element;
1406
+ }: DataTableFacetedFilterProps<TData, TValue>): react_jsx_runtime2.JSX.Element;
1408
1407
  //#endregion
1409
1408
  //#region src/components/data-table/data-table-pagination.d.ts
1410
1409
  interface DataTablePaginationProps<TData> extends React.ComponentProps<"div"> {
@@ -1416,7 +1415,7 @@ declare function DataTablePagination<TData>({
1416
1415
  pageSizeOptions,
1417
1416
  className,
1418
1417
  ...props
1419
- }: DataTablePaginationProps<TData>): react_jsx_runtime3.JSX.Element;
1418
+ }: DataTablePaginationProps<TData>): react_jsx_runtime2.JSX.Element;
1420
1419
  //#endregion
1421
1420
  //#region src/components/data-table/data-table-toolbar.d.ts
1422
1421
  interface DataTableToolbarProps<TData> extends React$1.ComponentProps<"div"> {
@@ -1427,7 +1426,7 @@ declare function DataTableToolbar<TData>({
1427
1426
  children,
1428
1427
  className,
1429
1428
  ...props
1430
- }: DataTableToolbarProps<TData>): react_jsx_runtime3.JSX.Element;
1429
+ }: DataTableToolbarProps<TData>): react_jsx_runtime2.JSX.Element;
1431
1430
  //#endregion
1432
1431
  //#region src/components/data-table/data-table-view-options.d.ts
1433
1432
  interface DataTableViewOptionsProps<TData> extends React$1.ComponentProps<typeof PopoverContent> {
@@ -1438,7 +1437,7 @@ declare function DataTableViewOptions<TData>({
1438
1437
  table,
1439
1438
  disabled,
1440
1439
  ...props
1441
- }: DataTableViewOptionsProps<TData>): react_jsx_runtime3.JSX.Element;
1440
+ }: DataTableViewOptionsProps<TData>): react_jsx_runtime2.JSX.Element;
1442
1441
  //#endregion
1443
1442
  //#region src/components/ui/multi-combobox.d.ts
1444
1443
  interface MultiComboboxOption {
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import * as _tanstack_react_table0 from "@tanstack/react-table";
4
4
  import { Column, ColumnDef, ColumnSort, Row, RowData, Table, TableOptions, TableState } from "@tanstack/react-table";
5
5
  import { Command, DropdownMenuTrigger, PopoverContent } from "@pixpilot/shadcn";
6
6
  import { ClassValue } from "clsx";
7
- import * as react_jsx_runtime2 from "react/jsx-runtime";
7
+ import * as react_jsx_runtime3 from "react/jsx-runtime";
8
8
  import { z } from "zod";
9
9
  import { ISchema } from "@formily/json-schema";
10
10
 
@@ -362,7 +362,7 @@ declare function AutoTableActionBar<TData>({
362
362
  enableDelete,
363
363
  extraActions,
364
364
  actions
365
- }: AutoTableActionBarProps<TData>): react_jsx_runtime2.JSX.Element;
365
+ }: AutoTableActionBarProps<TData>): react_jsx_runtime3.JSX.Element;
366
366
  //#endregion
367
367
  //#region src/lib/schema-bridge/types.d.ts
368
368
  /**
@@ -530,7 +530,7 @@ declare function AutoTable<T extends z.ZodObject<z.ZodRawShape>>({
530
530
  showDefaultExport,
531
531
  onSelectedCountChange,
532
532
  getSelectedRows
533
- }: AutoTableProps<T>): react_jsx_runtime2.JSX.Element;
533
+ }: AutoTableProps<T>): react_jsx_runtime3.JSX.Element;
534
534
  //#endregion
535
535
  //#region src/i18n/locale.d.ts
536
536
  /**
@@ -642,11 +642,10 @@ type AutoCrudDataSourceContext = {
642
642
  values?: Record<string, unknown>;
643
643
  signal?: AbortSignal;
644
644
  };
645
- type AutoCrudDataSourceLoader = (context: AutoCrudDataSourceContext) => Promise<AutoCrudOption[] | {
646
- options?: AutoCrudOption[];
647
- }> | AutoCrudOption[] | {
645
+ type AutoCrudDataSourceResult = AutoCrudOption[] | {
648
646
  options?: AutoCrudOption[];
649
647
  };
648
+ type AutoCrudDataSourceLoader = (context: AutoCrudDataSourceContext) => AutoCrudDataSourceResult | Promise<AutoCrudDataSourceResult>;
650
649
  type AutoCrudDataSourceConfig = string | {
651
650
  key: string;
652
651
  dependsOn?: string[];
@@ -672,9 +671,7 @@ declare function normalizeDataSourceConfig(config: AutoCrudDataSourceConfig | un
672
671
  dependsOn: string[];
673
672
  resetOnChange: boolean;
674
673
  } | undefined;
675
- declare function normalizeOptions(result: AutoCrudOption[] | {
676
- options?: AutoCrudOption[];
677
- } | undefined): AutoCrudOption[];
674
+ declare function normalizeOptions(result: AutoCrudDataSourceResult | undefined): AutoCrudOption[];
678
675
  //#endregion
679
676
  //#region src/components/auto-crud/auto-crud-table.d.ts
680
677
  /**
@@ -688,6 +685,8 @@ interface FilterConfig {
688
685
  variant?: 'text' | 'number' | 'range' | 'date' | 'dateRange' | 'boolean' | 'select' | 'multiSelect';
689
686
  /** select/multiSelect 的选项列表 */
690
687
  options?: FieldOption[];
688
+ /** select/multiSelect 的动态选项源 */
689
+ dataSource?: AutoCrudDataSourceConfig;
691
690
  /** range 的最小/最大值 */
692
691
  range?: [number, number];
693
692
  /** number 的单位 */
@@ -936,7 +935,7 @@ declare function AutoCrudTable<TSchema extends z.ZodObject<z.ZodRawShape>>({
936
935
  toolbarActions,
937
936
  locale: localeProp,
938
937
  onCreate
939
- }: AutoCrudTableProps<TSchema>): react_jsx_runtime2.JSX.Element;
938
+ }: AutoCrudTableProps<TSchema>): react_jsx_runtime3.JSX.Element;
940
939
  //#endregion
941
940
  //#region src/components/auto-crud/auto-form.d.ts
942
941
  interface AutoFormProps<T extends z.ZodObject<z.ZodRawShape>> {
@@ -968,7 +967,7 @@ declare function AutoFormInner<T extends z.ZodObject<z.ZodRawShape>>({
968
967
  labelAlign,
969
968
  labelWidth,
970
969
  showSubmitButton
971
- }: AutoFormProps<T>, ref: React.Ref<AutoFormRef>): react_jsx_runtime2.JSX.Element;
970
+ }: AutoFormProps<T>, ref: React.Ref<AutoFormRef>): react_jsx_runtime3.JSX.Element;
972
971
  declare const AutoForm: <T extends z.ZodObject<z.ZodRawShape>>(props: AutoFormProps<T> & {
973
972
  ref?: React.Ref<AutoFormRef>;
974
973
  }) => ReturnType<typeof AutoFormInner>;
@@ -1182,12 +1181,12 @@ declare const filterItemSchema: z.ZodObject<{
1182
1181
  variant: z.ZodEnum<{
1183
1182
  number: "number";
1184
1183
  boolean: "boolean";
1185
- date: "date";
1186
1184
  text: "text";
1185
+ range: "range";
1186
+ date: "date";
1187
+ dateRange: "dateRange";
1187
1188
  select: "select";
1188
1189
  multiSelect: "multiSelect";
1189
- dateRange: "dateRange";
1190
- range: "range";
1191
1190
  }>;
1192
1191
  operator: z.ZodEnum<{
1193
1192
  iLike: "iLike";
@@ -1270,7 +1269,7 @@ declare function AutoTableSimpleFilters<TData>({
1270
1269
  filters: externalFilters,
1271
1270
  onFiltersChange,
1272
1271
  leading
1273
- }: AutoTableSimpleFiltersProps<TData>): react_jsx_runtime2.JSX.Element | null;
1272
+ }: AutoTableSimpleFiltersProps<TData>): react_jsx_runtime3.JSX.Element | null;
1274
1273
  //#endregion
1275
1274
  //#region src/components/auto-crud/form-modal.d.ts
1276
1275
  type ModalVariant = "dialog" | "sheet";
@@ -1312,7 +1311,7 @@ declare function CrudFormModal<T extends z.ZodObject<z.ZodRawShape>>({
1312
1311
  labelAlign,
1313
1312
  labelWidth,
1314
1313
  className
1315
- }: CrudFormModalProps<T>): react_jsx_runtime2.JSX.Element;
1314
+ }: CrudFormModalProps<T>): react_jsx_runtime3.JSX.Element;
1316
1315
  //#endregion
1317
1316
  //#region src/components/auto-crud/import-dialog.d.ts
1318
1317
  interface ImportDialogProps {
@@ -1334,7 +1333,7 @@ declare function ImportDialog({
1334
1333
  columns,
1335
1334
  title,
1336
1335
  locale
1337
- }: ImportDialogProps): react_jsx_runtime2.JSX.Element;
1336
+ }: ImportDialogProps): react_jsx_runtime3.JSX.Element;
1338
1337
  //#endregion
1339
1338
  //#region src/components/auto-crud/export-dialog.d.ts
1340
1339
  type ExportMode = "selected" | "filtered";
@@ -1354,7 +1353,7 @@ declare function ExportDialog({
1354
1353
  selectedCount,
1355
1354
  onExport,
1356
1355
  canExportFiltered
1357
- }: ExportDialogProps): react_jsx_runtime2.JSX.Element;
1356
+ }: ExportDialogProps): react_jsx_runtime3.JSX.Element;
1358
1357
  //#endregion
1359
1358
  //#region src/components/data-table/data-table.d.ts
1360
1359
  interface DataTableProps<TData> extends React$1.ComponentProps<"div"> {
@@ -1367,7 +1366,7 @@ declare function DataTable<TData>({
1367
1366
  children,
1368
1367
  className,
1369
1368
  ...props
1370
- }: DataTableProps<TData>): react_jsx_runtime2.JSX.Element;
1369
+ }: DataTableProps<TData>): react_jsx_runtime3.JSX.Element;
1371
1370
  //#endregion
1372
1371
  //#region src/components/data-table/data-table-advanced-toolbar.d.ts
1373
1372
  interface DataTableAdvancedToolbarProps<TData> extends React$1.ComponentProps<"div"> {
@@ -1378,7 +1377,7 @@ declare function DataTableAdvancedToolbar<TData>({
1378
1377
  children,
1379
1378
  className,
1380
1379
  ...props
1381
- }: DataTableAdvancedToolbarProps<TData>): react_jsx_runtime2.JSX.Element;
1380
+ }: DataTableAdvancedToolbarProps<TData>): react_jsx_runtime3.JSX.Element;
1382
1381
  //#endregion
1383
1382
  //#region src/components/data-table/data-table-column-header.d.ts
1384
1383
  interface DataTableColumnHeaderProps<TData, TValue> extends React.ComponentProps<typeof DropdownMenuTrigger> {
@@ -1390,7 +1389,7 @@ declare function DataTableColumnHeader<TData, TValue>({
1390
1389
  label,
1391
1390
  className,
1392
1391
  ...props
1393
- }: DataTableColumnHeaderProps<TData, TValue>): react_jsx_runtime2.JSX.Element;
1392
+ }: DataTableColumnHeaderProps<TData, TValue>): react_jsx_runtime3.JSX.Element;
1394
1393
  //#endregion
1395
1394
  //#region src/components/data-table/data-table-faceted-filter.d.ts
1396
1395
  interface DataTableFacetedFilterProps<TData, TValue> {
@@ -1404,7 +1403,7 @@ declare function DataTableFacetedFilter<TData, TValue>({
1404
1403
  title,
1405
1404
  options,
1406
1405
  multiple
1407
- }: DataTableFacetedFilterProps<TData, TValue>): react_jsx_runtime2.JSX.Element;
1406
+ }: DataTableFacetedFilterProps<TData, TValue>): react_jsx_runtime3.JSX.Element;
1408
1407
  //#endregion
1409
1408
  //#region src/components/data-table/data-table-pagination.d.ts
1410
1409
  interface DataTablePaginationProps<TData> extends React.ComponentProps<"div"> {
@@ -1416,7 +1415,7 @@ declare function DataTablePagination<TData>({
1416
1415
  pageSizeOptions,
1417
1416
  className,
1418
1417
  ...props
1419
- }: DataTablePaginationProps<TData>): react_jsx_runtime2.JSX.Element;
1418
+ }: DataTablePaginationProps<TData>): react_jsx_runtime3.JSX.Element;
1420
1419
  //#endregion
1421
1420
  //#region src/components/data-table/data-table-toolbar.d.ts
1422
1421
  interface DataTableToolbarProps<TData> extends React$1.ComponentProps<"div"> {
@@ -1427,7 +1426,7 @@ declare function DataTableToolbar<TData>({
1427
1426
  children,
1428
1427
  className,
1429
1428
  ...props
1430
- }: DataTableToolbarProps<TData>): react_jsx_runtime2.JSX.Element;
1429
+ }: DataTableToolbarProps<TData>): react_jsx_runtime3.JSX.Element;
1431
1430
  //#endregion
1432
1431
  //#region src/components/data-table/data-table-view-options.d.ts
1433
1432
  interface DataTableViewOptionsProps<TData> extends React$1.ComponentProps<typeof PopoverContent> {
@@ -1438,7 +1437,7 @@ declare function DataTableViewOptions<TData>({
1438
1437
  table,
1439
1438
  disabled,
1440
1439
  ...props
1441
- }: DataTableViewOptionsProps<TData>): react_jsx_runtime2.JSX.Element;
1440
+ }: DataTableViewOptionsProps<TData>): react_jsx_runtime3.JSX.Element;
1442
1441
  //#endregion
1443
1442
  //#region src/components/ui/multi-combobox.d.ts
1444
1443
  interface MultiComboboxOption {
package/dist/index.js CHANGED
@@ -5193,65 +5193,59 @@ function createEditFormSchema(schema, options) {
5193
5193
  //#endregion
5194
5194
  //#region src/lib/registries.ts
5195
5195
  function createRegistry(label) {
5196
- const items = /* @__PURE__ */ new Map();
5196
+ const entries = /* @__PURE__ */ new Map();
5197
5197
  const listeners = /* @__PURE__ */ new Set();
5198
- let notifyQueued = false;
5199
5198
  const notify = () => {
5200
- if (notifyQueued) return;
5201
- notifyQueued = true;
5202
5199
  queueMicrotask(() => {
5203
- notifyQueued = false;
5204
- listeners.forEach((listener) => listener());
5200
+ for (const listener of listeners) listener();
5205
5201
  });
5206
5202
  };
5207
5203
  return {
5208
5204
  register(name, value) {
5209
- const current = items.get(name);
5210
- if (current === value) return;
5211
- if (current !== void 0) {
5205
+ if (entries.has(name)) {
5212
5206
  console.warn(`[AutoCrud] ${label} "${name}" is already registered.`);
5213
5207
  return;
5214
5208
  }
5215
- items.set(name, value);
5209
+ entries.set(name, value);
5216
5210
  notify();
5217
5211
  },
5218
5212
  unregister(name) {
5219
- if (!items.delete(name)) return;
5213
+ if (!entries.delete(name)) return;
5220
5214
  notify();
5221
5215
  },
5222
5216
  get(name) {
5223
- return items.get(name);
5217
+ return entries.get(name);
5224
5218
  },
5225
5219
  all() {
5226
- return Object.fromEntries(items);
5220
+ return Object.fromEntries(entries);
5227
5221
  },
5228
5222
  subscribe(listener) {
5229
5223
  listeners.add(listener);
5230
- return () => {
5231
- listeners.delete(listener);
5232
- };
5224
+ return () => listeners.delete(listener);
5233
5225
  }
5234
5226
  };
5235
5227
  }
5236
5228
  const formComponents = createRegistry("form component");
5237
5229
  const dataSources = createRegistry("data source");
5238
5230
  function normalizeDataSourceConfig(config) {
5239
- if (!config) return void 0;
5240
- if (typeof config === "string") return {
5231
+ if (typeof config === "string") return config.length > 0 ? {
5241
5232
  key: config,
5242
5233
  dependsOn: [],
5243
5234
  resetOnChange: false
5244
- };
5235
+ } : void 0;
5236
+ if (!config?.key) return void 0;
5245
5237
  return {
5246
5238
  key: config.key,
5247
- dependsOn: config.dependsOn ?? [],
5248
- resetOnChange: config.resetOnChange ?? false
5239
+ dependsOn: Array.isArray(config.dependsOn) ? config.dependsOn : [],
5240
+ resetOnChange: config.resetOnChange === true
5249
5241
  };
5250
5242
  }
5251
5243
  function normalizeOptions(result) {
5252
5244
  const options = Array.isArray(result) ? result : result?.options;
5253
- if (!options) return [];
5254
- return options.map((option) => ({
5245
+ if (!Array.isArray(options)) return [];
5246
+ return options.filter((option) => {
5247
+ return typeof option === "object" && option !== null && typeof option.value === "string" && typeof option.label === "string";
5248
+ }).map((option) => ({
5255
5249
  ...option,
5256
5250
  value: String(option.value)
5257
5251
  }));
@@ -5305,7 +5299,7 @@ const defaultFieldComponents = {
5305
5299
  decorator: "FormItem"
5306
5300
  }
5307
5301
  };
5308
- function useRegistryVersion(subscribe) {
5302
+ function useRegistryVersion$1(subscribe) {
5309
5303
  const [version, setVersion] = useState(0);
5310
5304
  useEffect(() => subscribe(() => setVersion((current) => current + 1)), [subscribe]);
5311
5305
  return version;
@@ -5317,13 +5311,15 @@ function isDataSourceConfig(value) {
5317
5311
  }
5318
5312
  function collectDataSourceConfigs(schema, result = {}) {
5319
5313
  const properties = schema.properties;
5320
- if (!properties) return result;
5314
+ if (!properties || typeof properties !== "object") return result;
5321
5315
  for (const [key, property] of Object.entries(properties)) {
5322
- const customDataSource = property["x-data-source"];
5323
- const schemaDataSource = property.dataSource;
5316
+ if (!property || typeof property !== "object" || Array.isArray(property)) continue;
5317
+ const record = property;
5318
+ const customDataSource = record["x-data-source"];
5319
+ const schemaDataSource = record.dataSource;
5324
5320
  const dataSourceConfig = isDataSourceConfig(customDataSource) ? customDataSource : isDataSourceConfig(schemaDataSource) ? schemaDataSource : void 0;
5325
5321
  if (dataSourceConfig) result[key] = dataSourceConfig;
5326
- collectDataSourceConfigs(property, result);
5322
+ collectDataSourceConfigs(record, result);
5327
5323
  }
5328
5324
  return result;
5329
5325
  }
@@ -5332,7 +5328,7 @@ function useFormDataSources(form, schema) {
5332
5328
  const sourceEntries = Object.entries(collectDataSourceConfigs(schema)).map(([fieldName, config]) => {
5333
5329
  const normalized = normalizeDataSourceConfig(config);
5334
5330
  return normalized ? [fieldName, normalized] : void 0;
5335
- }).filter(Boolean);
5331
+ }).filter((entry) => entry !== void 0);
5336
5332
  if (sourceEntries.length === 0) return;
5337
5333
  let active = true;
5338
5334
  const effectId = Symbol("autoCrudDataSources");
@@ -5368,14 +5364,12 @@ function useFormDataSources(form, schema) {
5368
5364
  };
5369
5365
  for (const [fieldName, source] of sourceEntries) loadFieldOptions(fieldName, source);
5370
5366
  form.addEffects(effectId, () => {
5371
- new Set(sourceEntries.flatMap(([, source]) => source.dependsOn)).forEach((dependency) => {
5372
- onFieldValueChange(dependency, () => {
5373
- sourceEntries.forEach(([fieldName, source]) => {
5374
- if (!source.dependsOn.includes(dependency)) return;
5375
- if (source.resetOnChange) form.setValuesIn(fieldName, void 0);
5376
- loadFieldOptions(fieldName, source);
5377
- });
5378
- });
5367
+ for (const dependency of new Set(sourceEntries.flatMap(([, source]) => source.dependsOn))) onFieldValueChange(dependency, () => {
5368
+ for (const [fieldName, source] of sourceEntries) {
5369
+ if (!source.dependsOn.includes(dependency)) continue;
5370
+ if (source.resetOnChange) form.setValuesIn(fieldName, void 0);
5371
+ loadFieldOptions(fieldName, source);
5372
+ }
5379
5373
  });
5380
5374
  });
5381
5375
  return () => {
@@ -5384,9 +5378,9 @@ function useFormDataSources(form, schema) {
5384
5378
  form.removeEffects(effectId);
5385
5379
  };
5386
5380
  }, [
5387
- useRegistryVersion(dataSources.subscribe),
5388
5381
  form,
5389
- schema
5382
+ schema,
5383
+ useRegistryVersion$1(dataSources.subscribe)
5390
5384
  ]);
5391
5385
  }
5392
5386
  function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides, mode = "create", loading = false, gridColumns = 1, labelAlign = "top", labelWidth, showSubmitButton = true }, ref) {
@@ -5407,7 +5401,7 @@ function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides,
5407
5401
  const fieldComponents = useMemo(() => ({ fields: {
5408
5402
  ...defaultFieldComponents,
5409
5403
  ...formComponents.all()
5410
- } }), [useRegistryVersion(formComponents.subscribe)]);
5404
+ } }), [useRegistryVersion$1(formComponents.subscribe)]);
5411
5405
  useFormDataSources(form, formSchema);
5412
5406
  const handleSubmit = async () => {
5413
5407
  await form.validate();
@@ -6265,6 +6259,69 @@ function toBatchOptions(options) {
6265
6259
  value
6266
6260
  }));
6267
6261
  }
6262
+ function getFilterDataSource(config) {
6263
+ if (config.filter && typeof config.filter === "object") return config.filter.dataSource ?? config.dataSource;
6264
+ return config.dataSource;
6265
+ }
6266
+ function shouldLoadDynamicFilterOptions(config) {
6267
+ if (config.filter === false) return false;
6268
+ if (normalizeFieldOptions(config.enum)) return false;
6269
+ if (config.filter && typeof config.filter === "object") {
6270
+ if (config.filter.enabled === false || config.filter.hidden === true) return false;
6271
+ if (normalizeFieldOptions(config.filter.options)) return false;
6272
+ }
6273
+ return normalizeDataSourceConfig(getFilterDataSource(config)) !== void 0;
6274
+ }
6275
+ function useRegistryVersion(subscribe) {
6276
+ const [version, setVersion] = React.useState(0);
6277
+ React.useEffect(() => subscribe(() => setVersion((current) => current + 1)), [subscribe]);
6278
+ return version;
6279
+ }
6280
+ function useDynamicFilterOptions(fields) {
6281
+ const registryVersion = useRegistryVersion(dataSources.subscribe);
6282
+ const [optionsByField, setOptionsByField] = React.useState({});
6283
+ const sourceEntries = React.useMemo(() => {
6284
+ if (!fields) return [];
6285
+ return Object.entries(fields).flatMap(([field, config]) => {
6286
+ if (!shouldLoadDynamicFilterOptions(config)) return [];
6287
+ const source = normalizeDataSourceConfig(getFilterDataSource(config));
6288
+ return source ? [{
6289
+ field,
6290
+ source
6291
+ }] : [];
6292
+ });
6293
+ }, [fields]);
6294
+ React.useEffect(() => {
6295
+ if (sourceEntries.length === 0) {
6296
+ setOptionsByField({});
6297
+ return;
6298
+ }
6299
+ let active = true;
6300
+ const controller = typeof AbortController === "undefined" ? void 0 : new AbortController();
6301
+ Promise.all(sourceEntries.map(async ({ field, source }) => {
6302
+ const loader = dataSources.get(source.key);
6303
+ if (!loader) return [field, []];
6304
+ try {
6305
+ return [field, normalizeOptions(await loader({
6306
+ field,
6307
+ values: {},
6308
+ signal: controller?.signal
6309
+ }))];
6310
+ } catch (error) {
6311
+ if (!controller?.signal.aborted) console.warn(`[AutoCrud] Failed to load filter data source "${source.key}".`, error);
6312
+ return [field, []];
6313
+ }
6314
+ })).then((entries) => {
6315
+ if (!active) return;
6316
+ setOptionsByField(Object.fromEntries(entries));
6317
+ });
6318
+ return () => {
6319
+ active = false;
6320
+ controller?.abort();
6321
+ };
6322
+ }, [sourceEntries, registryVersion]);
6323
+ return optionsByField;
6324
+ }
6268
6325
  function getOptionLabel(value, options) {
6269
6326
  const stringValue = String(value);
6270
6327
  return options?.find((option) => option.value === stringValue)?.label ?? stringValue;
@@ -6273,15 +6330,21 @@ function getOptionLabel(value, options) {
6273
6330
  * 从统一配置生成表格 overrides
6274
6331
  * 当 filter 配置存在时,合并到 meta 中(不影响列隐藏)
6275
6332
  */
6276
- function buildTableOverrides(fields, legacyOverrides) {
6333
+ function buildTableOverrides(fields, legacyOverrides, dynamicFilterOptions) {
6277
6334
  const result = { ...legacyOverrides };
6278
6335
  if (fields) for (const [key, config] of Object.entries(fields)) {
6279
- const tableOptions = toTableOptions(normalizeFieldOptions(config.enum));
6336
+ const fieldOptions = normalizeFieldOptions(config.enum);
6337
+ const tableOptions = toTableOptions(fieldOptions);
6338
+ const dynamicOptions = !fieldOptions ? toTableOptions(normalizeFieldOptions(dynamicFilterOptions?.[key])) : void 0;
6280
6339
  const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
6281
6340
  const fieldEnumMeta = tableOptions ? {
6282
6341
  options: tableOptions,
6283
6342
  variant: "multiSelect"
6284
6343
  } : void 0;
6344
+ const fieldDataSourceMeta = dynamicOptions ? {
6345
+ options: dynamicOptions,
6346
+ variant: "multiSelect"
6347
+ } : void 0;
6285
6348
  let filterMeta;
6286
6349
  if (config.filter && typeof config.filter === "object") {
6287
6350
  if (config.filter.enabled !== false && config.filter.hidden !== true) {
@@ -6299,11 +6362,12 @@ function buildTableOverrides(fields, legacyOverrides) {
6299
6362
  enableColumnFilter: false
6300
6363
  };
6301
6364
  }
6302
- if (fieldEnumMeta || tableMeta || filterMeta) result[key] = {
6365
+ if (fieldEnumMeta || fieldDataSourceMeta || tableMeta || filterMeta) result[key] = {
6303
6366
  ...result[key],
6304
6367
  meta: {
6305
6368
  ...result[key]?.meta ?? {},
6306
6369
  ...fieldEnumMeta ?? {},
6370
+ ...fieldDataSourceMeta ?? {},
6307
6371
  ...tableMeta ?? {},
6308
6372
  ...filterMeta ?? {}
6309
6373
  }
@@ -6616,6 +6680,7 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
6616
6680
  const [selectedCount, setSelectedCount] = React.useState(0);
6617
6681
  const [exporting, setExporting] = React.useState(false);
6618
6682
  const getSelectedRowsRef = React.useRef(null);
6683
+ const dynamicFilterOptions = useDynamicFilterOptions(resolvedFields);
6619
6684
  const importColumns = React.useMemo(() => {
6620
6685
  const shape = resolvedSchema.shape;
6621
6686
  const denySet = new Set(denyFields ?? []);
@@ -6652,7 +6717,11 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
6652
6717
  setExporting(false);
6653
6718
  }
6654
6719
  }, [selectedCount, handleExport]);
6655
- const tableOverrides = React.useMemo(() => buildTableOverrides(resolvedFields, tableConfig?.overrides), [resolvedFields, tableConfig?.overrides]);
6720
+ const tableOverrides = React.useMemo(() => buildTableOverrides(resolvedFields, tableConfig?.overrides, dynamicFilterOptions), [
6721
+ resolvedFields,
6722
+ tableConfig?.overrides,
6723
+ dynamicFilterOptions
6724
+ ]);
6656
6725
  const formOverrides = React.useMemo(() => buildFormOverrides(resolvedFields, formConfig?.overrides, denyFields), [
6657
6726
  resolvedFields,
6658
6727
  formConfig?.overrides,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wordrhyme/auto-crud",
3
3
  "type": "module",
4
- "version": "1.1.8",
4
+ "version": "1.2.0",
5
5
  "description": "Schema-first CRUD components with auto-generated tables and forms",
6
6
  "author": "wordrhyme",
7
7
  "license": "MIT",
@@ -66,8 +66,8 @@
66
66
  "tailwind-merge": "^3.5.0",
67
67
  "vaul": "^1.1.2",
68
68
  "@pixpilot/formily-shadcn": "1.11.20",
69
- "@pixpilot/shadcn": "1.2.7",
70
- "@pixpilot/shadcn-ui": "1.21.1"
69
+ "@pixpilot/shadcn-ui": "1.21.1",
70
+ "@pixpilot/shadcn": "1.2.7"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@tanstack/react-query": "^5.90.15",
@@ -84,9 +84,9 @@
84
84
  "typescript": "^5.9.3",
85
85
  "@internal/eslint-config": "0.3.0",
86
86
  "@internal/prettier-config": "0.0.1",
87
- "@internal/tsconfig": "0.1.0",
88
87
  "@internal/tsdown-config": "0.1.0",
89
- "@internal/vitest-config": "0.1.0"
88
+ "@internal/vitest-config": "0.1.0",
89
+ "@internal/tsconfig": "0.1.0"
90
90
  },
91
91
  "prettier": "@internal/prettier-config",
92
92
  "scripts": {