@wordrhyme/auto-crud 1.5.4 → 1.5.6

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
@@ -405,6 +405,21 @@ function useDateFormatterVersion() {
405
405
  function getHostDateFormatter() {
406
406
  return hostDateFormatters[hostDateFormatters.length - 1]?.formatter;
407
407
  }
408
+ const canonicalDatePattern = /^(\d{4})-(\d{2})-(\d{2})$/;
409
+ const canonicalDateTimePrefixPattern = /^(\d{4})-(\d{2})-(\d{2})(?=[T ])/;
410
+ function isValidCalendarDate(year, month, day) {
411
+ if (!year || !month || !day) return false;
412
+ const date = /* @__PURE__ */ new Date(`${year}-${month}-${day}T00:00:00.000Z`);
413
+ return !Number.isNaN(date.getTime()) && date.getUTCFullYear() === Number(year) && date.getUTCMonth() + 1 === Number(month) && date.getUTCDate() === Number(day);
414
+ }
415
+ function isValidCanonicalDate(value) {
416
+ const match = canonicalDatePattern.exec(value);
417
+ return !!match && isValidCalendarDate(match[1], match[2], match[3]);
418
+ }
419
+ function hasValidCanonicalDateTimePrefix(value) {
420
+ const match = canonicalDateTimePrefixPattern.exec(value);
421
+ return !match || isValidCalendarDate(match[1], match[2], match[3]);
422
+ }
408
423
  /**
409
424
  * Register the host's process-wide date presentation policy without coupling
410
425
  * AutoCrud to locale or timezone selection. The returned cleanup removes only
@@ -431,18 +446,45 @@ function setDateFormatter(formatter) {
431
446
  if (hostDateFormatters.length !== previousLength && getHostDateFormatter() !== currentFormatter) notifyDateFormatterChange();
432
447
  };
433
448
  }
434
- function formatDate(date, opts = {}) {
449
+ function formatDate(date, opts = {}, preset) {
435
450
  if (date === void 0) return "";
451
+ if (preset === "date" && typeof date === "string" && canonicalDatePattern.test(date)) return isValidCanonicalDate(date) ? date : "";
452
+ if (preset === "datetime" && typeof date === "string" && !hasValidCanonicalDateTimePrefix(date)) return "";
436
453
  try {
437
454
  const value = new Date(date);
455
+ if (Number.isNaN(value.getTime())) return "";
438
456
  const options = {
439
- month: opts.month ?? "long",
440
- day: opts.day ?? "numeric",
457
+ month: opts.month ?? (preset ? "2-digit" : "long"),
458
+ day: opts.day ?? (preset ? "2-digit" : "numeric"),
441
459
  year: opts.year ?? "numeric",
460
+ ...preset === "datetime" ? {
461
+ hour: opts.hour ?? "2-digit",
462
+ minute: opts.minute ?? "2-digit",
463
+ second: opts.second ?? "2-digit",
464
+ hourCycle: opts.hourCycle ?? "h23"
465
+ } : {},
442
466
  ...opts
443
467
  };
444
468
  const hostDateFormatter = getHostDateFormatter();
445
- return hostDateFormatter ? hostDateFormatter(value, options) : new Intl.DateTimeFormat("en-US", options).format(value);
469
+ if (hostDateFormatter) return preset ? hostDateFormatter(value, options, preset) : hostDateFormatter(value, options);
470
+ if (preset) {
471
+ const parts = new Intl.DateTimeFormat("en-CA", {
472
+ timeZone: opts.timeZone,
473
+ year: "numeric",
474
+ month: "2-digit",
475
+ day: "2-digit",
476
+ ...preset === "datetime" ? {
477
+ hour: "2-digit",
478
+ minute: "2-digit",
479
+ second: "2-digit",
480
+ hourCycle: "h23"
481
+ } : {}
482
+ }).formatToParts(value);
483
+ const read = (type) => parts.find((part) => part.type === type)?.value ?? "";
484
+ const formattedDate = `${read("year")}-${read("month")}-${read("day")}`;
485
+ return preset === "datetime" ? `${formattedDate} ${read("hour")}:${read("minute")}:${read("second")}` : formattedDate;
486
+ }
487
+ return new Intl.DateTimeFormat("en-US", options).format(value);
446
488
  } catch {
447
489
  return "";
448
490
  }
@@ -3194,6 +3236,10 @@ function renderCell(value, type, options) {
3194
3236
  className: "text-muted-foreground",
3195
3237
  children: "-"
3196
3238
  });
3239
+ if (Array.isArray(value) && value.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3240
+ className: "text-muted-foreground",
3241
+ children: "-"
3242
+ });
3197
3243
  const formatOptionValue = (optionValue) => {
3198
3244
  const stringValue = String(optionValue);
3199
3245
  return options?.find((option) => option.value === stringValue)?.label ?? stringValue;
@@ -5978,6 +6024,16 @@ function mergeFields(base, override) {
5978
6024
  const keys = new Set([...Object.keys(base ?? {}), ...Object.keys(override ?? {})]);
5979
6025
  return Object.fromEntries(Array.from(keys).map((key) => [key, mergeFieldConfig(base?.[key], override?.[key])]));
5980
6026
  }
6027
+ function applyResourceTablePresentation(fields, resourceFields) {
6028
+ if (!fields || !resourceFields) return fields;
6029
+ return Object.fromEntries(Object.entries(fields).map(([key, config]) => {
6030
+ const table = resourceFields[key]?.table;
6031
+ return [key, table === void 0 ? config : {
6032
+ ...config,
6033
+ table: mergeFieldPart(config.table, table)
6034
+ }];
6035
+ }));
6036
+ }
5981
6037
  function normalizeFieldOptions(options) {
5982
6038
  if (!options || options.length === 0) return void 0;
5983
6039
  return options.map((option) => ({
@@ -5985,6 +6041,18 @@ function normalizeFieldOptions(options) {
5985
6041
  value: String(option.value)
5986
6042
  }));
5987
6043
  }
6044
+ function getTableConfig(config) {
6045
+ return config.table && typeof config.table === "object" ? config.table : void 0;
6046
+ }
6047
+ function getTableOptions(config) {
6048
+ const table = getTableConfig(config);
6049
+ if (table?.options) return normalizeFieldOptions(table.options);
6050
+ if (table?.dataSource) return void 0;
6051
+ return normalizeFieldOptions(config.enum);
6052
+ }
6053
+ function getTableDataSource(config) {
6054
+ return getTableConfig(config)?.dataSource ?? config.dataSource;
6055
+ }
5988
6056
  function toTableOptions(options) {
5989
6057
  return options?.map(({ label, value, searchText, count, icon }) => ({
5990
6058
  label,
@@ -6060,8 +6128,8 @@ function mergeOptionsByField(left, right) {
6060
6128
  function shouldResolveOptions(field, config, hiddenColumns) {
6061
6129
  if (!config) return false;
6062
6130
  if (hiddenColumns.has(field)) return false;
6063
- if (normalizeFieldOptions(config.enum)) return false;
6064
- return normalizeDataSourceConfig(config.dataSource) !== void 0;
6131
+ if (getTableOptions(config) && !getTableConfig(config)?.dataSource) return false;
6132
+ return normalizeDataSourceConfig(getTableDataSource(config)) !== void 0;
6065
6133
  }
6066
6134
  function useRegistryVersion(subscribe) {
6067
6135
  const [version$1, setVersion] = react.useState(0);
@@ -6306,7 +6374,7 @@ function useDynamicResolveOptions(fields, rows, hiddenColumns) {
6306
6374
  const hiddenSet = new Set(hiddenColumns);
6307
6375
  return Object.entries(fields).flatMap(([field, config]) => {
6308
6376
  if (!shouldResolveOptions(field, config, hiddenSet)) return [];
6309
- const source = normalizeDataSourceConfig(config.dataSource);
6377
+ const source = normalizeDataSourceConfig(getTableDataSource(config));
6310
6378
  const values = getResolveValues(rows, field);
6311
6379
  return source && values.length > 0 ? [{
6312
6380
  field,
@@ -6403,12 +6471,16 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
6403
6471
  const result = { ...legacyOverrides };
6404
6472
  if (fields) for (const [key, config] of Object.entries(fields)) {
6405
6473
  const fieldOptions = normalizeFieldOptions(config.enum);
6474
+ const tableConfig = getTableConfig(config);
6475
+ const presentationOptions = getTableOptions(config);
6406
6476
  const tableOptions = toTableOptions(fieldOptions);
6407
6477
  const filterDataSourceRegistered = dynamicFilterState?.registeredByField[key];
6408
6478
  const filterDataSourceSearchable = dynamicFilterState?.searchableByField[key];
6409
6479
  const currentDynamicOptions = !fieldOptions && filterDataSourceRegistered ? toTableOptions(dynamicFilterState?.optionsByField[key] ?? []) : void 0;
6410
- const mergedDynamicOptions = mergeFieldOptions(!fieldOptions && filterDataSourceRegistered ? dynamicFilterState?.labelOptionsByField[key] ?? dynamicFilterState?.optionsByField[key] ?? [] : void 0, !fieldOptions ? dynamicResolveState?.optionsByField[key] : void 0);
6411
- const dynamicOptions = !fieldOptions && mergedDynamicOptions ? toTableOptions(mergedDynamicOptions) : void 0;
6480
+ const dynamicFilterLabelOptions = !fieldOptions && filterDataSourceRegistered ? dynamicFilterState?.labelOptionsByField[key] ?? dynamicFilterState?.optionsByField[key] ?? [] : void 0;
6481
+ const dynamicResolveOptions = dynamicResolveState?.optionsByField[key];
6482
+ const mergedSharedDynamicOptions = mergeFieldOptions(dynamicFilterLabelOptions, tableConfig?.dataSource ? void 0 : dynamicResolveOptions);
6483
+ const dynamicOptions = !fieldOptions && mergedSharedDynamicOptions ? toTableOptions(mergedSharedDynamicOptions) : void 0;
6412
6484
  const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
6413
6485
  const fieldEnumMeta = tableOptions ? {
6414
6486
  options: tableOptions,
@@ -6472,11 +6544,24 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
6472
6544
  hidden: true
6473
6545
  };
6474
6546
  else if (config.table && typeof config.table === "object") {
6475
- const { meta,...tableProps } = config.table;
6547
+ const { meta, display,...tableProps } = config.table;
6548
+ delete tableProps.options;
6549
+ delete tableProps.dataSource;
6476
6550
  result[key] = {
6477
6551
  ...result[key],
6478
6552
  ...tableProps
6479
6553
  };
6554
+ const hasTableLabels = config.table.options !== void 0 || config.table.dataSource !== void 0;
6555
+ if (display && display !== "auto" || hasTableLabels) {
6556
+ const options = tableConfig?.dataSource ? mergeFieldOptions(dynamicResolveOptions, presentationOptions) : presentationOptions ?? mergedSharedDynamicOptions;
6557
+ result[key] = {
6558
+ ...result[key],
6559
+ cell: ({ row }) => renderFieldValue(row.getValue(key), "string", {
6560
+ true: "true",
6561
+ false: "false"
6562
+ }, options, display ?? "auto")
6563
+ };
6564
+ }
6480
6565
  }
6481
6566
  }
6482
6567
  return result;
@@ -6524,7 +6609,9 @@ function buildHiddenColumns(fields, legacyHidden, denyFields, legacyOverrides) {
6524
6609
  for (const key of DEFAULT_HIDDEN_AUDIT_FIELDS) if (!legacyHiddenSet.has(key) && !denySet.has(key) && isTableOverrideExplicitlyVisible(legacyOverrides?.[key])) hidden.delete(key);
6525
6610
  if (fields) for (const [key, config] of Object.entries(fields)) {
6526
6611
  if (isDefaultHiddenAuditField(key) && !legacyHiddenSet.has(key) && !denySet.has(key) && isFieldTableExplicitlyVisible(config)) hidden.delete(key);
6527
- if (config.hidden) hidden.add(key);
6612
+ if (config.table && typeof config.table === "object" && config.table.hidden === false) {
6613
+ if (!legacyHiddenSet.has(key) && !denySet.has(key)) hidden.delete(key);
6614
+ } else if (config.hidden) hidden.add(key);
6528
6615
  else if (config.table === false) hidden.add(key);
6529
6616
  else if (config.table && typeof config.table === "object" && config.table.hidden) hidden.add(key);
6530
6617
  }
@@ -6574,12 +6661,36 @@ function buildBatchUpdateFields(schema, batchFields, fields) {
6574
6661
  /**
6575
6662
  * 渲染字段值
6576
6663
  */
6577
- function renderFieldValue(value, type, booleanLocale, options) {
6664
+ function renderFieldValue(value, type, booleanLocale, options, display = "auto") {
6578
6665
  if (value === null || value === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6579
6666
  className: "text-muted-foreground",
6580
6667
  children: "-"
6581
6668
  });
6582
- if (options && options.length > 0) {
6669
+ if (Array.isArray(value) && value.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6670
+ className: "text-muted-foreground",
6671
+ children: "-"
6672
+ });
6673
+ const renderText = (item) => getOptionLabel(item, options);
6674
+ if (display === "text") return Array.isArray(value) ? value.map(renderText).join(", ") : renderText(value);
6675
+ if (display === "date" || display === "datetime") return formatDate(value, {}, display);
6676
+ if (display === "badge" && (!options || options.length === 0)) {
6677
+ if (Array.isArray(value)) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6678
+ className: "flex gap-1 flex-wrap",
6679
+ children: [value.slice(0, 5).map((item, index$1) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
6680
+ variant: "secondary",
6681
+ children: String(item)
6682
+ }, index$1)), value.length > 5 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Badge, {
6683
+ variant: "outline",
6684
+ children: ["+", value.length - 5]
6685
+ })]
6686
+ });
6687
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
6688
+ variant: "outline",
6689
+ className: "capitalize",
6690
+ children: String(value)
6691
+ });
6692
+ }
6693
+ if ((display === "badge" || display === "auto") && options && options.length > 0) {
6583
6694
  if (Array.isArray(value)) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6584
6695
  className: "flex gap-1 flex-wrap",
6585
6696
  children: [value.slice(0, 5).map((v, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
@@ -6771,7 +6882,7 @@ function resolveActions(actionsOrFn, defaults, rowActionsLocale, context) {
6771
6882
  function AutoCrudTable({ id, title, description, schema, resource, fields, table: tableConfig, form: formConfig, permissions, actions: actionItems, toolbar, toolbarActions, locale: localeProp, onCreate }) {
6772
6883
  const locale = resolveLocale(localeProp);
6773
6884
  const resolvedSchema = resource.schema ?? schema;
6774
- const resolvedFields = react.useMemo(() => mergeFields(resource.fields, fields) ?? {}, [fields, resource.fields]);
6885
+ const resolvedFields = react.useMemo(() => applyResourceTablePresentation(mergeFields(resource.fields, fields), resource.fields) ?? {}, [fields, resource.fields]);
6775
6886
  const can = {
6776
6887
  create: permissions?.can?.create ?? true,
6777
6888
  update: permissions?.can?.update ?? true,
@@ -6794,7 +6905,18 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
6794
6905
  tableConfig?.overrides
6795
6906
  ]);
6796
6907
  const dynamicResolveOptions = useDynamicResolveOptions(resolvedFields, resource.tableData.data, hiddenColumns);
6797
- const dynamicOptionsByField = react.useMemo(() => mergeOptionsByField(dynamicFilterOptions.labelOptionsByField, dynamicResolveOptions.optionsByField), [dynamicFilterOptions.labelOptionsByField, dynamicResolveOptions.optionsByField]);
6908
+ const sharedResolveOptions = useDynamicResolveOptions(react.useMemo(() => Object.fromEntries(Object.entries(resolvedFields).flatMap(([field, config]) => {
6909
+ const table = getTableConfig(config);
6910
+ if (table?.options === void 0 && table?.dataSource === void 0) return [];
6911
+ const { table: _table,...sharedConfig } = config;
6912
+ return [[field, sharedConfig]];
6913
+ })), [resolvedFields]), resource.tableData.data, hiddenColumns);
6914
+ const viewDynamicOptionsByField = react.useMemo(() => mergeOptionsByField(mergeOptionsByField(dynamicFilterOptions.labelOptionsByField, sharedResolveOptions.optionsByField), Object.fromEntries(Object.entries(dynamicResolveOptions.optionsByField).filter(([field]) => !getTableConfig(resolvedFields[field] ?? {})?.dataSource))), [
6915
+ dynamicFilterOptions.labelOptionsByField,
6916
+ dynamicResolveOptions.optionsByField,
6917
+ sharedResolveOptions.optionsByField,
6918
+ resolvedFields
6919
+ ]);
6798
6920
  const resourceIdKey = resource.idKey ?? "id";
6799
6921
  const actionRegistryVersion = useCrudActionsVersion();
6800
6922
  const unifiedActions = react.useMemo(() => {
@@ -7126,7 +7248,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
7126
7248
  data: resource.modal.selected,
7127
7249
  schema: resolvedSchema,
7128
7250
  fields: resolvedFields,
7129
- dynamicOptions: dynamicOptionsByField,
7251
+ dynamicOptions: viewDynamicOptionsByField,
7130
7252
  denyFields,
7131
7253
  locale
7132
7254
  }),
package/dist/index.d.cts CHANGED
@@ -808,6 +808,7 @@ interface FieldOption {
808
808
  icon?: React$1.FC<React$1.SVGProps<SVGSVGElement>>;
809
809
  disabled?: boolean;
810
810
  }
811
+ type FieldTableDisplay = 'auto' | 'text' | 'badge' | 'date' | 'datetime';
811
812
  /**
812
813
  * 统一字段配置
813
814
  * 支持共用配置 + 表格/表单特定配置
@@ -838,8 +839,16 @@ interface Field {
838
839
  table?: {
839
840
  /** 是否在表格中隐藏 */
840
841
  hidden?: boolean;
842
+ /** 表格列标签 */
843
+ label?: string;
841
844
  /** 排序权重,数值越小越靠前 */
842
845
  index?: number;
846
+ /** 仅用于表格展示的静态值标签;与 dataSource 同时配置时覆盖同值的动态标签 */
847
+ options?: FieldOption[];
848
+ /** 仅用于表格展示的动态值标签源 */
849
+ dataSource?: AutoCrudDataSourceConfig;
850
+ /** 声明式单元格展示模式;非 auto 模式会覆盖拥有方自定义 cell */
851
+ display?: FieldTableDisplay;
843
852
  /** 筛选器配置 */
844
853
  meta?: Record<string, unknown>;
845
854
  /** 其他列配置 */
@@ -1337,12 +1346,12 @@ declare const filterItemSchema: z.ZodObject<{
1337
1346
  variant: z.ZodEnum<{
1338
1347
  number: "number";
1339
1348
  boolean: "boolean";
1340
- text: "text";
1341
- range: "range";
1342
1349
  date: "date";
1343
- dateRange: "dateRange";
1350
+ text: "text";
1344
1351
  select: "select";
1345
1352
  multiSelect: "multiSelect";
1353
+ dateRange: "dateRange";
1354
+ range: "range";
1346
1355
  }>;
1347
1356
  operator: z.ZodEnum<{
1348
1357
  iLike: "iLike";
@@ -1904,7 +1913,8 @@ declare function createMemoryDataSource<T extends {
1904
1913
  }>(initialData?: T[]): DataSource<T>;
1905
1914
  //#endregion
1906
1915
  //#region src/lib/format.d.ts
1907
- type DateFormatter = (date: Date, options: Intl.DateTimeFormatOptions) => string;
1916
+ type DateFormatPreset = 'date' | 'datetime';
1917
+ type DateFormatter = (date: Date, options: Intl.DateTimeFormatOptions, preset?: DateFormatPreset) => string;
1908
1918
  /**
1909
1919
  * Register the host's process-wide date presentation policy without coupling
1910
1920
  * AutoCrud to locale or timezone selection. The returned cleanup removes only
@@ -1912,7 +1922,7 @@ type DateFormatter = (date: Date, options: Intl.DateTimeFormatOptions) => string
1912
1922
  * Passing undefined clears every registration.
1913
1923
  */
1914
1924
  declare function setDateFormatter(formatter?: DateFormatter): () => void;
1915
- declare function formatDate(date: Date | string | number | undefined, opts?: Intl.DateTimeFormatOptions): string;
1925
+ declare function formatDate(date: Date | string | number | undefined, opts?: Intl.DateTimeFormatOptions, preset?: DateFormatPreset): string;
1916
1926
  //#endregion
1917
1927
  //#region src/lib/humanize.d.ts
1918
1928
  /**
@@ -1992,4 +2002,4 @@ declare function exportAllToCSV<T extends Record<string, unknown>>(data: T[], op
1992
2002
  */
1993
2003
  declare function downloadCSVTemplate(headers: string[], filename?: string): void;
1994
2004
  //#endregion
1995
- export { type ActionConfig, type ActionItem, type ActionsColumnConfig, type AutoCrudActionConfig, type AutoCrudActionsConfig, type AutoCrudDataSourceConfig, type AutoCrudDataSourceContext, type AutoCrudDataSourceEntry, type AutoCrudDataSourceLoader, type AutoCrudDataSourceRegistration, type AutoCrudFormComponentConfig, type AutoCrudLocale, type AutoCrudOption, type AutoCrudQueryCapabilities, type AutoCrudRowActionContext, AutoCrudTable, type AutoCrudTableProps, type AutoCrudToolbarContext, type AutoCrudToolbarResolver, AutoForm, type AutoFormProps, type AutoQueryParams, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, type BatchActionConfig, type BatchActionContext, type BatchActionItem, type BatchBuiltinActionItem, type BatchBuiltinActionType, type BatchCustomActionItem, type BatchUpdateField, type ColumnOverrides, type CreateFormSchemaOptions, type CreateTableSchemaOptions, type CrudActionBase, type CrudActionEntry, type CrudActionRegistration, type CrudActionZone, CrudFormModal, type CrudHooks, type CrudOperationPermissions, type CrudPermissions, type DataSource, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableRowAction, DataTableToolbar, DataTableViewOptions, type DateFormatter, type EnumOption, ExportDialog, type ExportDialogProps, type ExportMode, ExtendedColumnFilter, ExtendedColumnSort, type Field, type FieldOption, type FieldType, type Fields, type FilterConfig, FilterOperator, type FilterVariant, type FormSchemaOverrides, ImportDialog, type ImportDialogProps, type ImportResult, type JSONSchema, type JSONSchemaProperty, JoinOperator, type ListParams, type ListResult, type LocaleProp, MultiCombobox, type MultiComboboxOption, type MultiComboboxProps, type MultiComboboxTriggerRenderProps, Option, type ParsedImportData, type ParsedZodField, type Parser, QueryKeys, type RowActionConfig, type RowActionItem, type RowBuiltinActionItem, type RowBuiltinActionType, type RowCustomActionItem, SchemaAdapter, Select, type SelectMode, type SelectOption, type SelectProps, type SelectSearchableDynamicProps, type SelectSearchableMultipleProps, type SelectSearchableProps, type SelectSearchableSingleProps, type SelectSimpleProps, type SelectTriggerRenderProps, type SimpleFieldConfig, type SimpleFieldsConfig, type ToastAdapter, type ToolbarActionConfig, type ToolbarActionItem, type ToolbarBuiltinActionItem, type ToolbarBuiltinActionType, type ToolbarCustomActionItem, type UnifiedField, type UnifiedSchema, type UrlStateOptions, type UseAutoCrudResourceOptions, type UseAutoCrudResourceParams, type UseAutoCrudResourceReturn, cn, coerceRowValues, components, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, crudActions, dataSources, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formComponents, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, normalizeDataSourceConfig, normalizeOptions, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setDateFormatter, setSearchParams, setToolbarResolver, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
2005
+ export { type ActionConfig, type ActionItem, type ActionsColumnConfig, type AutoCrudActionConfig, type AutoCrudActionsConfig, type AutoCrudDataSourceConfig, type AutoCrudDataSourceContext, type AutoCrudDataSourceEntry, type AutoCrudDataSourceLoader, type AutoCrudDataSourceRegistration, type AutoCrudFormComponentConfig, type AutoCrudLocale, type AutoCrudOption, type AutoCrudQueryCapabilities, type AutoCrudRowActionContext, AutoCrudTable, type AutoCrudTableProps, type AutoCrudToolbarContext, type AutoCrudToolbarResolver, AutoForm, type AutoFormProps, type AutoQueryParams, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, type BatchActionConfig, type BatchActionContext, type BatchActionItem, type BatchBuiltinActionItem, type BatchBuiltinActionType, type BatchCustomActionItem, type BatchUpdateField, type ColumnOverrides, type CreateFormSchemaOptions, type CreateTableSchemaOptions, type CrudActionBase, type CrudActionEntry, type CrudActionRegistration, type CrudActionZone, CrudFormModal, type CrudHooks, type CrudOperationPermissions, type CrudPermissions, type DataSource, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableRowAction, DataTableToolbar, DataTableViewOptions, type DateFormatPreset, type DateFormatter, type EnumOption, ExportDialog, type ExportDialogProps, type ExportMode, ExtendedColumnFilter, ExtendedColumnSort, type Field, type FieldOption, type FieldTableDisplay, type FieldType, type Fields, type FilterConfig, FilterOperator, type FilterVariant, type FormSchemaOverrides, ImportDialog, type ImportDialogProps, type ImportResult, type JSONSchema, type JSONSchemaProperty, JoinOperator, type ListParams, type ListResult, type LocaleProp, MultiCombobox, type MultiComboboxOption, type MultiComboboxProps, type MultiComboboxTriggerRenderProps, Option, type ParsedImportData, type ParsedZodField, type Parser, QueryKeys, type RowActionConfig, type RowActionItem, type RowBuiltinActionItem, type RowBuiltinActionType, type RowCustomActionItem, SchemaAdapter, Select, type SelectMode, type SelectOption, type SelectProps, type SelectSearchableDynamicProps, type SelectSearchableMultipleProps, type SelectSearchableProps, type SelectSearchableSingleProps, type SelectSimpleProps, type SelectTriggerRenderProps, type SimpleFieldConfig, type SimpleFieldsConfig, type ToastAdapter, type ToolbarActionConfig, type ToolbarActionItem, type ToolbarBuiltinActionItem, type ToolbarBuiltinActionType, type ToolbarCustomActionItem, type UnifiedField, type UnifiedSchema, type UrlStateOptions, type UseAutoCrudResourceOptions, type UseAutoCrudResourceParams, type UseAutoCrudResourceReturn, cn, coerceRowValues, components, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, crudActions, dataSources, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formComponents, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, normalizeDataSourceConfig, normalizeOptions, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setDateFormatter, setSearchParams, setToolbarResolver, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import * as _tanstack_react_table0 from "@tanstack/react-table";
3
3
  import { Column, ColumnDef, ColumnSort, Row, RowData, Table, TableOptions, TableState } from "@tanstack/react-table";
4
4
  import { DropdownMenuTrigger, PopoverContent } from "@wordrhyme/shadcn";
5
5
  import { ClassValue } from "clsx";
6
- import * as react_jsx_runtime2 from "react/jsx-runtime";
6
+ import * as react_jsx_runtime3 from "react/jsx-runtime";
7
7
  import { MultiCombobox, MultiComboboxOption, MultiComboboxProps, MultiComboboxTriggerRenderProps, Select, SelectMode, SelectOption, SelectProps, SelectSearchableDynamicProps, SelectSearchableMultipleProps, SelectSearchableProps, SelectSearchableSingleProps, SelectSimpleProps, SelectTriggerRenderProps } from "@wordrhyme/shadcn-ui";
8
8
  import { z } from "zod";
9
9
  import { JsonSchemaFormScope } from "@wordrhyme/formily-shadcn";
@@ -413,7 +413,7 @@ declare function AutoTableActionBar<TData>({
413
413
  extraActions,
414
414
  actions,
415
415
  deleteConfirmation
416
- }: AutoTableActionBarProps<TData>): react_jsx_runtime2.JSX.Element;
416
+ }: AutoTableActionBarProps<TData>): react_jsx_runtime3.JSX.Element;
417
417
  //#endregion
418
418
  //#region src/lib/schema-bridge/types.d.ts
419
419
  /**
@@ -592,7 +592,7 @@ declare function AutoTable<T extends z.ZodObject<z.ZodRawShape>>({
592
592
  onSelectedCountChange,
593
593
  onSelectedRowsChange,
594
594
  getSelectedRows
595
- }: AutoTableProps<T>): react_jsx_runtime2.JSX.Element;
595
+ }: AutoTableProps<T>): react_jsx_runtime3.JSX.Element;
596
596
  //#endregion
597
597
  //#region src/i18n/locale.d.ts
598
598
  /**
@@ -808,6 +808,7 @@ interface FieldOption {
808
808
  icon?: React$1.FC<React$1.SVGProps<SVGSVGElement>>;
809
809
  disabled?: boolean;
810
810
  }
811
+ type FieldTableDisplay = 'auto' | 'text' | 'badge' | 'date' | 'datetime';
811
812
  /**
812
813
  * 统一字段配置
813
814
  * 支持共用配置 + 表格/表单特定配置
@@ -838,8 +839,16 @@ interface Field {
838
839
  table?: {
839
840
  /** 是否在表格中隐藏 */
840
841
  hidden?: boolean;
842
+ /** 表格列标签 */
843
+ label?: string;
841
844
  /** 排序权重,数值越小越靠前 */
842
845
  index?: number;
846
+ /** 仅用于表格展示的静态值标签;与 dataSource 同时配置时覆盖同值的动态标签 */
847
+ options?: FieldOption[];
848
+ /** 仅用于表格展示的动态值标签源 */
849
+ dataSource?: AutoCrudDataSourceConfig;
850
+ /** 声明式单元格展示模式;非 auto 模式会覆盖拥有方自定义 cell */
851
+ display?: FieldTableDisplay;
843
852
  /** 筛选器配置 */
844
853
  meta?: Record<string, unknown>;
845
854
  /** 其他列配置 */
@@ -1084,7 +1093,7 @@ declare function AutoCrudTable<TSchema extends z.ZodObject<z.ZodRawShape>>({
1084
1093
  toolbarActions,
1085
1094
  locale: localeProp,
1086
1095
  onCreate
1087
- }: AutoCrudTableProps<TSchema>): react_jsx_runtime2.JSX.Element;
1096
+ }: AutoCrudTableProps<TSchema>): react_jsx_runtime3.JSX.Element;
1088
1097
  //#endregion
1089
1098
  //#region src/components/auto-crud/auto-form.d.ts
1090
1099
  interface AutoFormProps<T extends z.ZodObject<z.ZodRawShape>> {
@@ -1123,7 +1132,7 @@ declare function AutoFormInner<T extends z.ZodObject<z.ZodRawShape>>({
1123
1132
  labelAlign,
1124
1133
  labelWidth,
1125
1134
  showSubmitButton
1126
- }: AutoFormProps<T>, ref: React.Ref<AutoFormRef>): react_jsx_runtime2.JSX.Element;
1135
+ }: AutoFormProps<T>, ref: React.Ref<AutoFormRef>): react_jsx_runtime3.JSX.Element;
1127
1136
  declare const AutoForm: <T extends z.ZodObject<z.ZodRawShape>>(props: AutoFormProps<T> & {
1128
1137
  ref?: React.Ref<AutoFormRef>;
1129
1138
  }) => ReturnType<typeof AutoFormInner>;
@@ -1337,12 +1346,12 @@ declare const filterItemSchema: z.ZodObject<{
1337
1346
  variant: z.ZodEnum<{
1338
1347
  number: "number";
1339
1348
  boolean: "boolean";
1340
- text: "text";
1341
- range: "range";
1342
1349
  date: "date";
1343
- dateRange: "dateRange";
1350
+ text: "text";
1344
1351
  select: "select";
1345
1352
  multiSelect: "multiSelect";
1353
+ dateRange: "dateRange";
1354
+ range: "range";
1346
1355
  }>;
1347
1356
  operator: z.ZodEnum<{
1348
1357
  iLike: "iLike";
@@ -1439,7 +1448,7 @@ declare function AutoTableSimpleFilters<TData>({
1439
1448
  filters: externalFilters,
1440
1449
  onFiltersChange,
1441
1450
  leading
1442
- }: AutoTableSimpleFiltersProps<TData>): react_jsx_runtime2.JSX.Element | null;
1451
+ }: AutoTableSimpleFiltersProps<TData>): react_jsx_runtime3.JSX.Element | null;
1443
1452
  //#endregion
1444
1453
  //#region src/components/auto-crud/form-modal.d.ts
1445
1454
  type ModalVariant = 'dialog' | 'sheet';
@@ -1483,7 +1492,7 @@ declare function CrudFormModal<T extends z.ZodObject<z.ZodRawShape>>({
1483
1492
  labelAlign,
1484
1493
  labelWidth,
1485
1494
  className
1486
- }: CrudFormModalProps<T>): react_jsx_runtime2.JSX.Element;
1495
+ }: CrudFormModalProps<T>): react_jsx_runtime3.JSX.Element;
1487
1496
  //#endregion
1488
1497
  //#region src/components/auto-crud/import-dialog.d.ts
1489
1498
  interface ImportDialogProps {
@@ -1505,7 +1514,7 @@ declare function ImportDialog({
1505
1514
  columns,
1506
1515
  title,
1507
1516
  locale
1508
- }: ImportDialogProps): react_jsx_runtime2.JSX.Element;
1517
+ }: ImportDialogProps): react_jsx_runtime3.JSX.Element;
1509
1518
  //#endregion
1510
1519
  //#region src/components/auto-crud/export-dialog.d.ts
1511
1520
  type ExportMode = 'selected' | 'filtered';
@@ -1525,7 +1534,7 @@ declare function ExportDialog({
1525
1534
  selectedCount,
1526
1535
  onExport,
1527
1536
  canExportFiltered
1528
- }: ExportDialogProps): react_jsx_runtime2.JSX.Element;
1537
+ }: ExportDialogProps): react_jsx_runtime3.JSX.Element;
1529
1538
  //#endregion
1530
1539
  //#region src/components/data-table/data-table.d.ts
1531
1540
  interface DataTableProps<TData> extends React$1.ComponentProps<'div'> {
@@ -1538,7 +1547,7 @@ declare function DataTable<TData>({
1538
1547
  children,
1539
1548
  className,
1540
1549
  ...props
1541
- }: DataTableProps<TData>): react_jsx_runtime2.JSX.Element;
1550
+ }: DataTableProps<TData>): react_jsx_runtime3.JSX.Element;
1542
1551
  //#endregion
1543
1552
  //#region src/components/data-table/data-table-advanced-toolbar.d.ts
1544
1553
  interface DataTableAdvancedToolbarProps<TData> extends React$1.ComponentProps<'div'> {
@@ -1549,7 +1558,7 @@ declare function DataTableAdvancedToolbar<TData>({
1549
1558
  children,
1550
1559
  className,
1551
1560
  ...props
1552
- }: DataTableAdvancedToolbarProps<TData>): react_jsx_runtime2.JSX.Element;
1561
+ }: DataTableAdvancedToolbarProps<TData>): react_jsx_runtime3.JSX.Element;
1553
1562
  //#endregion
1554
1563
  //#region src/components/data-table/data-table-column-header.d.ts
1555
1564
  interface DataTableColumnHeaderProps<TData, TValue> extends React.ComponentProps<typeof DropdownMenuTrigger> {
@@ -1561,7 +1570,7 @@ declare function DataTableColumnHeader<TData, TValue>({
1561
1570
  label,
1562
1571
  className,
1563
1572
  ...props
1564
- }: DataTableColumnHeaderProps<TData, TValue>): react_jsx_runtime2.JSX.Element;
1573
+ }: DataTableColumnHeaderProps<TData, TValue>): react_jsx_runtime3.JSX.Element;
1565
1574
  //#endregion
1566
1575
  //#region src/components/data-table/data-table-faceted-filter.d.ts
1567
1576
  interface DataTableFacetedFilterProps<TData, TValue> {
@@ -1575,7 +1584,7 @@ declare function DataTableFacetedFilter<TData, TValue>({
1575
1584
  title,
1576
1585
  options,
1577
1586
  multiple
1578
- }: DataTableFacetedFilterProps<TData, TValue>): react_jsx_runtime2.JSX.Element;
1587
+ }: DataTableFacetedFilterProps<TData, TValue>): react_jsx_runtime3.JSX.Element;
1579
1588
  //#endregion
1580
1589
  //#region src/components/data-table/data-table-pagination.d.ts
1581
1590
  interface DataTablePaginationProps<TData> extends React.ComponentProps<'div'> {
@@ -1587,7 +1596,7 @@ declare function DataTablePagination<TData>({
1587
1596
  pageSizeOptions,
1588
1597
  className,
1589
1598
  ...props
1590
- }: DataTablePaginationProps<TData>): react_jsx_runtime2.JSX.Element;
1599
+ }: DataTablePaginationProps<TData>): react_jsx_runtime3.JSX.Element;
1591
1600
  //#endregion
1592
1601
  //#region src/components/data-table/data-table-toolbar.d.ts
1593
1602
  interface DataTableToolbarProps<TData> extends React$1.ComponentProps<'div'> {
@@ -1598,7 +1607,7 @@ declare function DataTableToolbar<TData>({
1598
1607
  children,
1599
1608
  className,
1600
1609
  ...props
1601
- }: DataTableToolbarProps<TData>): react_jsx_runtime2.JSX.Element;
1610
+ }: DataTableToolbarProps<TData>): react_jsx_runtime3.JSX.Element;
1602
1611
  //#endregion
1603
1612
  //#region src/components/data-table/data-table-view-options.d.ts
1604
1613
  interface DataTableViewOptionsProps<TData> extends React$1.ComponentProps<typeof PopoverContent> {
@@ -1609,7 +1618,7 @@ declare function DataTableViewOptions<TData>({
1609
1618
  table,
1610
1619
  disabled,
1611
1620
  ...props
1612
- }: DataTableViewOptionsProps<TData>): react_jsx_runtime2.JSX.Element;
1621
+ }: DataTableViewOptionsProps<TData>): react_jsx_runtime3.JSX.Element;
1613
1622
  //#endregion
1614
1623
  //#region src/lib/crud-actions.d.ts
1615
1624
  type CrudActionZone = 'toolbar' | 'row' | 'batch';
@@ -1904,7 +1913,8 @@ declare function createMemoryDataSource<T extends {
1904
1913
  }>(initialData?: T[]): DataSource<T>;
1905
1914
  //#endregion
1906
1915
  //#region src/lib/format.d.ts
1907
- type DateFormatter = (date: Date, options: Intl.DateTimeFormatOptions) => string;
1916
+ type DateFormatPreset = 'date' | 'datetime';
1917
+ type DateFormatter = (date: Date, options: Intl.DateTimeFormatOptions, preset?: DateFormatPreset) => string;
1908
1918
  /**
1909
1919
  * Register the host's process-wide date presentation policy without coupling
1910
1920
  * AutoCrud to locale or timezone selection. The returned cleanup removes only
@@ -1912,7 +1922,7 @@ type DateFormatter = (date: Date, options: Intl.DateTimeFormatOptions) => string
1912
1922
  * Passing undefined clears every registration.
1913
1923
  */
1914
1924
  declare function setDateFormatter(formatter?: DateFormatter): () => void;
1915
- declare function formatDate(date: Date | string | number | undefined, opts?: Intl.DateTimeFormatOptions): string;
1925
+ declare function formatDate(date: Date | string | number | undefined, opts?: Intl.DateTimeFormatOptions, preset?: DateFormatPreset): string;
1916
1926
  //#endregion
1917
1927
  //#region src/lib/humanize.d.ts
1918
1928
  /**
@@ -1992,4 +2002,4 @@ declare function exportAllToCSV<T extends Record<string, unknown>>(data: T[], op
1992
2002
  */
1993
2003
  declare function downloadCSVTemplate(headers: string[], filename?: string): void;
1994
2004
  //#endregion
1995
- export { type ActionConfig, type ActionItem, type ActionsColumnConfig, type AutoCrudActionConfig, type AutoCrudActionsConfig, type AutoCrudDataSourceConfig, type AutoCrudDataSourceContext, type AutoCrudDataSourceEntry, type AutoCrudDataSourceLoader, type AutoCrudDataSourceRegistration, type AutoCrudFormComponentConfig, type AutoCrudLocale, type AutoCrudOption, type AutoCrudQueryCapabilities, type AutoCrudRowActionContext, AutoCrudTable, type AutoCrudTableProps, type AutoCrudToolbarContext, type AutoCrudToolbarResolver, AutoForm, type AutoFormProps, type AutoQueryParams, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, type BatchActionConfig, type BatchActionContext, type BatchActionItem, type BatchBuiltinActionItem, type BatchBuiltinActionType, type BatchCustomActionItem, type BatchUpdateField, type ColumnOverrides, type CreateFormSchemaOptions, type CreateTableSchemaOptions, type CrudActionBase, type CrudActionEntry, type CrudActionRegistration, type CrudActionZone, CrudFormModal, type CrudHooks, type CrudOperationPermissions, type CrudPermissions, type DataSource, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableRowAction, DataTableToolbar, DataTableViewOptions, type DateFormatter, type EnumOption, ExportDialog, type ExportDialogProps, type ExportMode, ExtendedColumnFilter, ExtendedColumnSort, type Field, type FieldOption, type FieldType, type Fields, type FilterConfig, FilterOperator, type FilterVariant, type FormSchemaOverrides, ImportDialog, type ImportDialogProps, type ImportResult, type JSONSchema, type JSONSchemaProperty, JoinOperator, type ListParams, type ListResult, type LocaleProp, MultiCombobox, type MultiComboboxOption, type MultiComboboxProps, type MultiComboboxTriggerRenderProps, Option, type ParsedImportData, type ParsedZodField, type Parser, QueryKeys, type RowActionConfig, type RowActionItem, type RowBuiltinActionItem, type RowBuiltinActionType, type RowCustomActionItem, SchemaAdapter, Select, type SelectMode, type SelectOption, type SelectProps, type SelectSearchableDynamicProps, type SelectSearchableMultipleProps, type SelectSearchableProps, type SelectSearchableSingleProps, type SelectSimpleProps, type SelectTriggerRenderProps, type SimpleFieldConfig, type SimpleFieldsConfig, type ToastAdapter, type ToolbarActionConfig, type ToolbarActionItem, type ToolbarBuiltinActionItem, type ToolbarBuiltinActionType, type ToolbarCustomActionItem, type UnifiedField, type UnifiedSchema, type UrlStateOptions, type UseAutoCrudResourceOptions, type UseAutoCrudResourceParams, type UseAutoCrudResourceReturn, cn, coerceRowValues, components, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, crudActions, dataSources, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formComponents, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, normalizeDataSourceConfig, normalizeOptions, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setDateFormatter, setSearchParams, setToolbarResolver, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
2005
+ export { type ActionConfig, type ActionItem, type ActionsColumnConfig, type AutoCrudActionConfig, type AutoCrudActionsConfig, type AutoCrudDataSourceConfig, type AutoCrudDataSourceContext, type AutoCrudDataSourceEntry, type AutoCrudDataSourceLoader, type AutoCrudDataSourceRegistration, type AutoCrudFormComponentConfig, type AutoCrudLocale, type AutoCrudOption, type AutoCrudQueryCapabilities, type AutoCrudRowActionContext, AutoCrudTable, type AutoCrudTableProps, type AutoCrudToolbarContext, type AutoCrudToolbarResolver, AutoForm, type AutoFormProps, type AutoQueryParams, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, type BatchActionConfig, type BatchActionContext, type BatchActionItem, type BatchBuiltinActionItem, type BatchBuiltinActionType, type BatchCustomActionItem, type BatchUpdateField, type ColumnOverrides, type CreateFormSchemaOptions, type CreateTableSchemaOptions, type CrudActionBase, type CrudActionEntry, type CrudActionRegistration, type CrudActionZone, CrudFormModal, type CrudHooks, type CrudOperationPermissions, type CrudPermissions, type DataSource, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableRowAction, DataTableToolbar, DataTableViewOptions, type DateFormatPreset, type DateFormatter, type EnumOption, ExportDialog, type ExportDialogProps, type ExportMode, ExtendedColumnFilter, ExtendedColumnSort, type Field, type FieldOption, type FieldTableDisplay, type FieldType, type Fields, type FilterConfig, FilterOperator, type FilterVariant, type FormSchemaOverrides, ImportDialog, type ImportDialogProps, type ImportResult, type JSONSchema, type JSONSchemaProperty, JoinOperator, type ListParams, type ListResult, type LocaleProp, MultiCombobox, type MultiComboboxOption, type MultiComboboxProps, type MultiComboboxTriggerRenderProps, Option, type ParsedImportData, type ParsedZodField, type Parser, QueryKeys, type RowActionConfig, type RowActionItem, type RowBuiltinActionItem, type RowBuiltinActionType, type RowCustomActionItem, SchemaAdapter, Select, type SelectMode, type SelectOption, type SelectProps, type SelectSearchableDynamicProps, type SelectSearchableMultipleProps, type SelectSearchableProps, type SelectSearchableSingleProps, type SelectSimpleProps, type SelectTriggerRenderProps, type SimpleFieldConfig, type SimpleFieldsConfig, type ToastAdapter, type ToolbarActionConfig, type ToolbarActionItem, type ToolbarBuiltinActionItem, type ToolbarBuiltinActionType, type ToolbarCustomActionItem, type UnifiedField, type UnifiedSchema, type UrlStateOptions, type UseAutoCrudResourceOptions, type UseAutoCrudResourceParams, type UseAutoCrudResourceReturn, cn, coerceRowValues, components, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, crudActions, dataSources, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formComponents, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, normalizeDataSourceConfig, normalizeOptions, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setDateFormatter, setSearchParams, setToolbarResolver, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
package/dist/index.js CHANGED
@@ -368,6 +368,21 @@ function useDateFormatterVersion() {
368
368
  function getHostDateFormatter() {
369
369
  return hostDateFormatters[hostDateFormatters.length - 1]?.formatter;
370
370
  }
371
+ const canonicalDatePattern = /^(\d{4})-(\d{2})-(\d{2})$/;
372
+ const canonicalDateTimePrefixPattern = /^(\d{4})-(\d{2})-(\d{2})(?=[T ])/;
373
+ function isValidCalendarDate(year, month, day) {
374
+ if (!year || !month || !day) return false;
375
+ const date = /* @__PURE__ */ new Date(`${year}-${month}-${day}T00:00:00.000Z`);
376
+ return !Number.isNaN(date.getTime()) && date.getUTCFullYear() === Number(year) && date.getUTCMonth() + 1 === Number(month) && date.getUTCDate() === Number(day);
377
+ }
378
+ function isValidCanonicalDate(value) {
379
+ const match = canonicalDatePattern.exec(value);
380
+ return !!match && isValidCalendarDate(match[1], match[2], match[3]);
381
+ }
382
+ function hasValidCanonicalDateTimePrefix(value) {
383
+ const match = canonicalDateTimePrefixPattern.exec(value);
384
+ return !match || isValidCalendarDate(match[1], match[2], match[3]);
385
+ }
371
386
  /**
372
387
  * Register the host's process-wide date presentation policy without coupling
373
388
  * AutoCrud to locale or timezone selection. The returned cleanup removes only
@@ -394,18 +409,45 @@ function setDateFormatter(formatter) {
394
409
  if (hostDateFormatters.length !== previousLength && getHostDateFormatter() !== currentFormatter) notifyDateFormatterChange();
395
410
  };
396
411
  }
397
- function formatDate(date, opts = {}) {
412
+ function formatDate(date, opts = {}, preset) {
398
413
  if (date === void 0) return "";
414
+ if (preset === "date" && typeof date === "string" && canonicalDatePattern.test(date)) return isValidCanonicalDate(date) ? date : "";
415
+ if (preset === "datetime" && typeof date === "string" && !hasValidCanonicalDateTimePrefix(date)) return "";
399
416
  try {
400
417
  const value = new Date(date);
418
+ if (Number.isNaN(value.getTime())) return "";
401
419
  const options = {
402
- month: opts.month ?? "long",
403
- day: opts.day ?? "numeric",
420
+ month: opts.month ?? (preset ? "2-digit" : "long"),
421
+ day: opts.day ?? (preset ? "2-digit" : "numeric"),
404
422
  year: opts.year ?? "numeric",
423
+ ...preset === "datetime" ? {
424
+ hour: opts.hour ?? "2-digit",
425
+ minute: opts.minute ?? "2-digit",
426
+ second: opts.second ?? "2-digit",
427
+ hourCycle: opts.hourCycle ?? "h23"
428
+ } : {},
405
429
  ...opts
406
430
  };
407
431
  const hostDateFormatter = getHostDateFormatter();
408
- return hostDateFormatter ? hostDateFormatter(value, options) : new Intl.DateTimeFormat("en-US", options).format(value);
432
+ if (hostDateFormatter) return preset ? hostDateFormatter(value, options, preset) : hostDateFormatter(value, options);
433
+ if (preset) {
434
+ const parts = new Intl.DateTimeFormat("en-CA", {
435
+ timeZone: opts.timeZone,
436
+ year: "numeric",
437
+ month: "2-digit",
438
+ day: "2-digit",
439
+ ...preset === "datetime" ? {
440
+ hour: "2-digit",
441
+ minute: "2-digit",
442
+ second: "2-digit",
443
+ hourCycle: "h23"
444
+ } : {}
445
+ }).formatToParts(value);
446
+ const read = (type) => parts.find((part) => part.type === type)?.value ?? "";
447
+ const formattedDate = `${read("year")}-${read("month")}-${read("day")}`;
448
+ return preset === "datetime" ? `${formattedDate} ${read("hour")}:${read("minute")}:${read("second")}` : formattedDate;
449
+ }
450
+ return new Intl.DateTimeFormat("en-US", options).format(value);
409
451
  } catch {
410
452
  return "";
411
453
  }
@@ -3157,6 +3199,10 @@ function renderCell(value, type, options) {
3157
3199
  className: "text-muted-foreground",
3158
3200
  children: "-"
3159
3201
  });
3202
+ if (Array.isArray(value) && value.length === 0) return /* @__PURE__ */ jsx("span", {
3203
+ className: "text-muted-foreground",
3204
+ children: "-"
3205
+ });
3160
3206
  const formatOptionValue = (optionValue) => {
3161
3207
  const stringValue = String(optionValue);
3162
3208
  return options?.find((option) => option.value === stringValue)?.label ?? stringValue;
@@ -5941,6 +5987,16 @@ function mergeFields(base, override) {
5941
5987
  const keys = new Set([...Object.keys(base ?? {}), ...Object.keys(override ?? {})]);
5942
5988
  return Object.fromEntries(Array.from(keys).map((key) => [key, mergeFieldConfig(base?.[key], override?.[key])]));
5943
5989
  }
5990
+ function applyResourceTablePresentation(fields, resourceFields) {
5991
+ if (!fields || !resourceFields) return fields;
5992
+ return Object.fromEntries(Object.entries(fields).map(([key, config]) => {
5993
+ const table = resourceFields[key]?.table;
5994
+ return [key, table === void 0 ? config : {
5995
+ ...config,
5996
+ table: mergeFieldPart(config.table, table)
5997
+ }];
5998
+ }));
5999
+ }
5944
6000
  function normalizeFieldOptions(options) {
5945
6001
  if (!options || options.length === 0) return void 0;
5946
6002
  return options.map((option) => ({
@@ -5948,6 +6004,18 @@ function normalizeFieldOptions(options) {
5948
6004
  value: String(option.value)
5949
6005
  }));
5950
6006
  }
6007
+ function getTableConfig(config) {
6008
+ return config.table && typeof config.table === "object" ? config.table : void 0;
6009
+ }
6010
+ function getTableOptions(config) {
6011
+ const table = getTableConfig(config);
6012
+ if (table?.options) return normalizeFieldOptions(table.options);
6013
+ if (table?.dataSource) return void 0;
6014
+ return normalizeFieldOptions(config.enum);
6015
+ }
6016
+ function getTableDataSource(config) {
6017
+ return getTableConfig(config)?.dataSource ?? config.dataSource;
6018
+ }
5951
6019
  function toTableOptions(options) {
5952
6020
  return options?.map(({ label, value, searchText, count, icon }) => ({
5953
6021
  label,
@@ -6023,8 +6091,8 @@ function mergeOptionsByField(left, right) {
6023
6091
  function shouldResolveOptions(field, config, hiddenColumns) {
6024
6092
  if (!config) return false;
6025
6093
  if (hiddenColumns.has(field)) return false;
6026
- if (normalizeFieldOptions(config.enum)) return false;
6027
- return normalizeDataSourceConfig(config.dataSource) !== void 0;
6094
+ if (getTableOptions(config) && !getTableConfig(config)?.dataSource) return false;
6095
+ return normalizeDataSourceConfig(getTableDataSource(config)) !== void 0;
6028
6096
  }
6029
6097
  function useRegistryVersion(subscribe) {
6030
6098
  const [version$1, setVersion] = React.useState(0);
@@ -6269,7 +6337,7 @@ function useDynamicResolveOptions(fields, rows, hiddenColumns) {
6269
6337
  const hiddenSet = new Set(hiddenColumns);
6270
6338
  return Object.entries(fields).flatMap(([field, config]) => {
6271
6339
  if (!shouldResolveOptions(field, config, hiddenSet)) return [];
6272
- const source = normalizeDataSourceConfig(config.dataSource);
6340
+ const source = normalizeDataSourceConfig(getTableDataSource(config));
6273
6341
  const values = getResolveValues(rows, field);
6274
6342
  return source && values.length > 0 ? [{
6275
6343
  field,
@@ -6366,12 +6434,16 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
6366
6434
  const result = { ...legacyOverrides };
6367
6435
  if (fields) for (const [key, config] of Object.entries(fields)) {
6368
6436
  const fieldOptions = normalizeFieldOptions(config.enum);
6437
+ const tableConfig = getTableConfig(config);
6438
+ const presentationOptions = getTableOptions(config);
6369
6439
  const tableOptions = toTableOptions(fieldOptions);
6370
6440
  const filterDataSourceRegistered = dynamicFilterState?.registeredByField[key];
6371
6441
  const filterDataSourceSearchable = dynamicFilterState?.searchableByField[key];
6372
6442
  const currentDynamicOptions = !fieldOptions && filterDataSourceRegistered ? toTableOptions(dynamicFilterState?.optionsByField[key] ?? []) : void 0;
6373
- const mergedDynamicOptions = mergeFieldOptions(!fieldOptions && filterDataSourceRegistered ? dynamicFilterState?.labelOptionsByField[key] ?? dynamicFilterState?.optionsByField[key] ?? [] : void 0, !fieldOptions ? dynamicResolveState?.optionsByField[key] : void 0);
6374
- const dynamicOptions = !fieldOptions && mergedDynamicOptions ? toTableOptions(mergedDynamicOptions) : void 0;
6443
+ const dynamicFilterLabelOptions = !fieldOptions && filterDataSourceRegistered ? dynamicFilterState?.labelOptionsByField[key] ?? dynamicFilterState?.optionsByField[key] ?? [] : void 0;
6444
+ const dynamicResolveOptions = dynamicResolveState?.optionsByField[key];
6445
+ const mergedSharedDynamicOptions = mergeFieldOptions(dynamicFilterLabelOptions, tableConfig?.dataSource ? void 0 : dynamicResolveOptions);
6446
+ const dynamicOptions = !fieldOptions && mergedSharedDynamicOptions ? toTableOptions(mergedSharedDynamicOptions) : void 0;
6375
6447
  const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
6376
6448
  const fieldEnumMeta = tableOptions ? {
6377
6449
  options: tableOptions,
@@ -6435,11 +6507,24 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
6435
6507
  hidden: true
6436
6508
  };
6437
6509
  else if (config.table && typeof config.table === "object") {
6438
- const { meta,...tableProps } = config.table;
6510
+ const { meta, display,...tableProps } = config.table;
6511
+ delete tableProps.options;
6512
+ delete tableProps.dataSource;
6439
6513
  result[key] = {
6440
6514
  ...result[key],
6441
6515
  ...tableProps
6442
6516
  };
6517
+ const hasTableLabels = config.table.options !== void 0 || config.table.dataSource !== void 0;
6518
+ if (display && display !== "auto" || hasTableLabels) {
6519
+ const options = tableConfig?.dataSource ? mergeFieldOptions(dynamicResolveOptions, presentationOptions) : presentationOptions ?? mergedSharedDynamicOptions;
6520
+ result[key] = {
6521
+ ...result[key],
6522
+ cell: ({ row }) => renderFieldValue(row.getValue(key), "string", {
6523
+ true: "true",
6524
+ false: "false"
6525
+ }, options, display ?? "auto")
6526
+ };
6527
+ }
6443
6528
  }
6444
6529
  }
6445
6530
  return result;
@@ -6487,7 +6572,9 @@ function buildHiddenColumns(fields, legacyHidden, denyFields, legacyOverrides) {
6487
6572
  for (const key of DEFAULT_HIDDEN_AUDIT_FIELDS) if (!legacyHiddenSet.has(key) && !denySet.has(key) && isTableOverrideExplicitlyVisible(legacyOverrides?.[key])) hidden.delete(key);
6488
6573
  if (fields) for (const [key, config] of Object.entries(fields)) {
6489
6574
  if (isDefaultHiddenAuditField(key) && !legacyHiddenSet.has(key) && !denySet.has(key) && isFieldTableExplicitlyVisible(config)) hidden.delete(key);
6490
- if (config.hidden) hidden.add(key);
6575
+ if (config.table && typeof config.table === "object" && config.table.hidden === false) {
6576
+ if (!legacyHiddenSet.has(key) && !denySet.has(key)) hidden.delete(key);
6577
+ } else if (config.hidden) hidden.add(key);
6491
6578
  else if (config.table === false) hidden.add(key);
6492
6579
  else if (config.table && typeof config.table === "object" && config.table.hidden) hidden.add(key);
6493
6580
  }
@@ -6537,12 +6624,36 @@ function buildBatchUpdateFields(schema, batchFields, fields) {
6537
6624
  /**
6538
6625
  * 渲染字段值
6539
6626
  */
6540
- function renderFieldValue(value, type, booleanLocale, options) {
6627
+ function renderFieldValue(value, type, booleanLocale, options, display = "auto") {
6541
6628
  if (value === null || value === void 0) return /* @__PURE__ */ jsx("span", {
6542
6629
  className: "text-muted-foreground",
6543
6630
  children: "-"
6544
6631
  });
6545
- if (options && options.length > 0) {
6632
+ if (Array.isArray(value) && value.length === 0) return /* @__PURE__ */ jsx("span", {
6633
+ className: "text-muted-foreground",
6634
+ children: "-"
6635
+ });
6636
+ const renderText = (item) => getOptionLabel(item, options);
6637
+ if (display === "text") return Array.isArray(value) ? value.map(renderText).join(", ") : renderText(value);
6638
+ if (display === "date" || display === "datetime") return formatDate(value, {}, display);
6639
+ if (display === "badge" && (!options || options.length === 0)) {
6640
+ if (Array.isArray(value)) return /* @__PURE__ */ jsxs("div", {
6641
+ className: "flex gap-1 flex-wrap",
6642
+ children: [value.slice(0, 5).map((item, index$1) => /* @__PURE__ */ jsx(Badge, {
6643
+ variant: "secondary",
6644
+ children: String(item)
6645
+ }, index$1)), value.length > 5 && /* @__PURE__ */ jsxs(Badge, {
6646
+ variant: "outline",
6647
+ children: ["+", value.length - 5]
6648
+ })]
6649
+ });
6650
+ return /* @__PURE__ */ jsx(Badge, {
6651
+ variant: "outline",
6652
+ className: "capitalize",
6653
+ children: String(value)
6654
+ });
6655
+ }
6656
+ if ((display === "badge" || display === "auto") && options && options.length > 0) {
6546
6657
  if (Array.isArray(value)) return /* @__PURE__ */ jsxs("div", {
6547
6658
  className: "flex gap-1 flex-wrap",
6548
6659
  children: [value.slice(0, 5).map((v, i) => /* @__PURE__ */ jsx(Badge, {
@@ -6734,7 +6845,7 @@ function resolveActions(actionsOrFn, defaults, rowActionsLocale, context) {
6734
6845
  function AutoCrudTable({ id, title, description, schema, resource, fields, table: tableConfig, form: formConfig, permissions, actions: actionItems, toolbar, toolbarActions, locale: localeProp, onCreate }) {
6735
6846
  const locale = resolveLocale(localeProp);
6736
6847
  const resolvedSchema = resource.schema ?? schema;
6737
- const resolvedFields = React.useMemo(() => mergeFields(resource.fields, fields) ?? {}, [fields, resource.fields]);
6848
+ const resolvedFields = React.useMemo(() => applyResourceTablePresentation(mergeFields(resource.fields, fields), resource.fields) ?? {}, [fields, resource.fields]);
6738
6849
  const can = {
6739
6850
  create: permissions?.can?.create ?? true,
6740
6851
  update: permissions?.can?.update ?? true,
@@ -6757,7 +6868,18 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
6757
6868
  tableConfig?.overrides
6758
6869
  ]);
6759
6870
  const dynamicResolveOptions = useDynamicResolveOptions(resolvedFields, resource.tableData.data, hiddenColumns);
6760
- const dynamicOptionsByField = React.useMemo(() => mergeOptionsByField(dynamicFilterOptions.labelOptionsByField, dynamicResolveOptions.optionsByField), [dynamicFilterOptions.labelOptionsByField, dynamicResolveOptions.optionsByField]);
6871
+ const sharedResolveOptions = useDynamicResolveOptions(React.useMemo(() => Object.fromEntries(Object.entries(resolvedFields).flatMap(([field, config]) => {
6872
+ const table = getTableConfig(config);
6873
+ if (table?.options === void 0 && table?.dataSource === void 0) return [];
6874
+ const { table: _table,...sharedConfig } = config;
6875
+ return [[field, sharedConfig]];
6876
+ })), [resolvedFields]), resource.tableData.data, hiddenColumns);
6877
+ const viewDynamicOptionsByField = React.useMemo(() => mergeOptionsByField(mergeOptionsByField(dynamicFilterOptions.labelOptionsByField, sharedResolveOptions.optionsByField), Object.fromEntries(Object.entries(dynamicResolveOptions.optionsByField).filter(([field]) => !getTableConfig(resolvedFields[field] ?? {})?.dataSource))), [
6878
+ dynamicFilterOptions.labelOptionsByField,
6879
+ dynamicResolveOptions.optionsByField,
6880
+ sharedResolveOptions.optionsByField,
6881
+ resolvedFields
6882
+ ]);
6761
6883
  const resourceIdKey = resource.idKey ?? "id";
6762
6884
  const actionRegistryVersion = useCrudActionsVersion();
6763
6885
  const unifiedActions = React.useMemo(() => {
@@ -7089,7 +7211,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
7089
7211
  data: resource.modal.selected,
7090
7212
  schema: resolvedSchema,
7091
7213
  fields: resolvedFields,
7092
- dynamicOptions: dynamicOptionsByField,
7214
+ dynamicOptions: viewDynamicOptionsByField,
7093
7215
  denyFields,
7094
7216
  locale
7095
7217
  }),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wordrhyme/auto-crud",
3
3
  "type": "module",
4
- "version": "1.5.4",
4
+ "version": "1.5.6",
5
5
  "description": "Schema-first CRUD components with auto-generated tables and forms",
6
6
  "author": "wordrhyme",
7
7
  "license": "MIT",
@@ -84,9 +84,9 @@
84
84
  "tsdown": "^0.15.12",
85
85
  "typescript": "^5.9.3",
86
86
  "vitest": "^3.2.4",
87
- "@internal/prettier-config": "0.0.1",
88
- "@internal/tsconfig": "0.1.0",
89
87
  "@internal/eslint-config": "0.3.0",
88
+ "@internal/tsconfig": "0.1.0",
89
+ "@internal/prettier-config": "0.0.1",
90
90
  "@internal/tsdown-config": "0.1.0",
91
91
  "@internal/vitest-config": "0.1.0"
92
92
  },