@wordrhyme/auto-crud 1.8.1 → 1.9.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/README.md CHANGED
@@ -803,7 +803,7 @@ type ToolbarBuiltinActionItem = ActionMeta & {
803
803
  type ToolbarCustomActionItem = ActionMeta & {
804
804
  type: 'custom';
805
805
  component: React.ReactNode | ((context: AutoCrudToolbarContext) => React.ReactNode);
806
- position?: 'start' | 'end'; // 仅在无内置项时生效,默认 "end"
806
+ position?: ActionPosition; // start/end 仅无内置项时生效;也支持 { anchor, side }
807
807
  };
808
808
 
809
809
  interface AutoCrudToolbarContext {
@@ -911,6 +911,28 @@ crudActions.register({
911
911
  `order` 不再重排同一插件数组内的显示顺序。内置属性覆盖仍沿用原有的 action `order`、`ownerId`、注册序优先级,最后一个配置生效。
912
912
  使用 `order` 排列同一插件操作的旧调用方,应把数组调整为所需顺序。最终权限过滤只移除不可用的内置操作,不改变其余操作顺序或授予权限。
913
913
 
914
+ ### 统一位置契约
915
+
916
+ AutoCrud action 和 WordRhyme PluginSlot 共用 `ActionPosition`:`"start"`、`"end"`,或 `{ anchor, side: "before" | "after" }`。类型、schema、位置匹配和锚点排序从不依赖 React 的 `@wordrhyme/auto-crud/position` 导出。
917
+
918
+ `positionActions(ownerActions, fills)` 合并拥有方按钮和扩展数组:`start` fills 放在数组前,`end` 或未指定位置的 fills 放在数组后,相对位置按基础按钮锚点插入。AutoCrud 和 PluginSlot 共用此解析器。原有 action 数组及 start/end 排列规则保持不变。指定锚点时,在原有合并、覆盖和隐藏之后定位,`order` 按升序排列同一锚点的 fills。AutoCrud 使用合并后基础 action 的 `id` 作为锚点;原生按钮未设置 `id` 时使用 `type`。合并后的动作列表不存在锚点时,不显示依赖它的扩展;最终权限过滤继续沿用已有行为。
919
+
920
+ ```tsx
921
+ crudActions.register({
922
+ targetId: 'com.wordrhyme.shop.products',
923
+ zone: 'toolbar',
924
+ ownerId: 'com.wordrhyme.sync',
925
+ actions: [
926
+ {
927
+ type: 'custom',
928
+ component: SyncButton,
929
+ position: { anchor: 'create', side: 'before' },
930
+ order: 30,
931
+ },
932
+ ],
933
+ });
934
+ ```
935
+
914
936
  ---
915
937
 
916
938
  ## 🎬 行操作配置
@@ -1005,7 +1027,7 @@ type RowCustomActionItem<T> = ActionMeta & {
1005
1027
  component?:
1006
1028
  | React.ReactNode
1007
1029
  | ((context: AutoCrudRowActionContext<T>) => React.ReactNode);
1008
- position?: 'start' | 'end'; // 仅无内置项时生效,默认 end
1030
+ position?: ActionPosition; // start/end 仅无内置项时生效;也支持 { anchor, side }
1009
1031
  separator?: boolean;
1010
1032
  variant?: 'default' | 'destructive';
1011
1033
  };
@@ -1629,6 +1651,14 @@ MIT © [wordrhyme](https://github.com/denvey/wordrhyme-components)
1629
1651
  - [Notion](https://notion.so) - 高级筛选器设计
1630
1652
  - [Linear](https://linear.app) - 命令面板设计
1631
1653
 
1654
+ ### Status badge colors
1655
+
1656
+ For `table.display: "badge"`, a scalar field's `table.options` entries may set `badgeTone` to `neutral`, `success`, `warning`, or `info`. This renders a tinted, outlined rounded label with a decorative dot. Labels remain readable without color; omitted tones retain the default badge. `display: "text"` is unaffected. Domain-specific state-to-tone mappings belong in the consuming plugin metadata.
1657
+
1658
+ Registered custom actions may set `before: "delete"` (or another builtin action type) to appear immediately before that action. If the builtin is absent, the existing `position` fallback applies. This only controls ordering and does not add or grant the target action.
1659
+
1660
+ Custom row components receive `MenuItem` in their action context. Use this supplied primitive instead of importing a menu item from another UI bundle: the menu root and item must share the same Radix runtime context. Prevent the select event's default dismissal when the component owns an open dialog, so the menu does not unmount the workflow.
1661
+
1632
1662
  ### Detail presentation
1633
1663
 
1634
1664
  Details automatically share field labels, `enum`/`dataSource` mappings and
@@ -1689,6 +1719,31 @@ is pinned to the already-published alpha.19 for reproducible ESM tests and type
1689
1719
  checks until alpha.20 is published; it is not the supported CommonJS runtime.
1690
1720
  The CommonJS export/identity regression belongs to the UI provider repository.
1691
1721
 
1722
+ ### Filter-only fields
1723
+
1724
+ Use `table: false` with an explicit `filter` to keep a field in the standard
1725
+ filter bar without rendering a data column. Shared `hidden`, permission `deny`,
1726
+ and explicit table exclusions still hide the filter. Pass the same filter
1727
+ configuration to the resource so URL values use the same variants/operators:
1728
+
1729
+ ```tsx
1730
+ const fields = {
1731
+ customerId: {
1732
+ label: 'Customer',
1733
+ table: false as const,
1734
+ form: false as const,
1735
+ filter: { variant: 'select' as const, dataSource: 'customers', index: 20 },
1736
+ },
1737
+ };
1738
+ const resource = useAutoCrudResource({ router, schema, fields });
1739
+ return <AutoCrudTable schema={schema} resource={resource} fields={fields} />;
1740
+ ```
1741
+
1742
+ The field must exist in the schema or resource metadata, and the server must
1743
+ resolve its filter. A data source loads options; it does not translate query
1744
+ conditions. Standard filters share URL state, Reset, and pagination. Dynamically
1745
+ registered schema fields hydrate existing URL values without resetting the page.
1746
+
1692
1747
  ### 按 ID 隐藏或替换自定义操作
1693
1748
 
1694
1749
  拥有方为 custom 操作声明稳定 `id` 后,扩展可以在相同 CRUD target 和操作区域
package/dist/index.cjs CHANGED
@@ -1,58 +1,36 @@
1
- //#region rolldown:runtime
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __copyProps = (to, from, except, desc) => {
9
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
- key = keys[i];
11
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
- get: ((k) => from[k]).bind(null, key),
13
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
- });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
- value: mod,
20
- enumerable: true
21
- }) : target, mod));
22
-
23
- //#endregion
1
+ const require_position = require('./position-BlO0bPw6.cjs');
24
2
  let react = require("react");
25
- react = __toESM(react);
3
+ react = require_position.__toESM(react);
26
4
  let lucide_react = require("lucide-react");
27
- lucide_react = __toESM(lucide_react);
5
+ lucide_react = require_position.__toESM(lucide_react);
28
6
  let __tanstack_react_table = require("@tanstack/react-table");
29
- __tanstack_react_table = __toESM(__tanstack_react_table);
7
+ __tanstack_react_table = require_position.__toESM(__tanstack_react_table);
30
8
  let __wordrhyme_shadcn = require("@wordrhyme/shadcn");
31
- __wordrhyme_shadcn = __toESM(__wordrhyme_shadcn);
9
+ __wordrhyme_shadcn = require_position.__toESM(__wordrhyme_shadcn);
32
10
  let clsx = require("clsx");
33
- clsx = __toESM(clsx);
11
+ clsx = require_position.__toESM(clsx);
34
12
  let tailwind_merge = require("tailwind-merge");
35
- tailwind_merge = __toESM(tailwind_merge);
13
+ tailwind_merge = require_position.__toESM(tailwind_merge);
36
14
  let react_jsx_runtime = require("react/jsx-runtime");
37
- react_jsx_runtime = __toESM(react_jsx_runtime);
15
+ react_jsx_runtime = require_position.__toESM(react_jsx_runtime);
38
16
  let nanoid = require("nanoid");
39
- nanoid = __toESM(nanoid);
17
+ nanoid = require_position.__toESM(nanoid);
40
18
  let __wordrhyme_shadcn_ui = require("@wordrhyme/shadcn-ui");
41
- __wordrhyme_shadcn_ui = __toESM(__wordrhyme_shadcn_ui);
19
+ __wordrhyme_shadcn_ui = require_position.__toESM(__wordrhyme_shadcn_ui);
42
20
  let __wordrhyme_ui = require("@wordrhyme/ui");
43
- __wordrhyme_ui = __toESM(__wordrhyme_ui);
21
+ __wordrhyme_ui = require_position.__toESM(__wordrhyme_ui);
44
22
  let zod = require("zod");
45
- zod = __toESM(zod);
23
+ zod = require_position.__toESM(zod);
46
24
  let __wordrhyme_formily_shadcn = require("@wordrhyme/formily-shadcn");
47
- __wordrhyme_formily_shadcn = __toESM(__wordrhyme_formily_shadcn);
25
+ __wordrhyme_formily_shadcn = require_position.__toESM(__wordrhyme_formily_shadcn);
48
26
  let __formily_core = require("@formily/core");
49
- __formily_core = __toESM(__formily_core);
27
+ __formily_core = require_position.__toESM(__formily_core);
50
28
  let __formily_reactive = require("@formily/reactive");
51
- __formily_reactive = __toESM(__formily_reactive);
29
+ __formily_reactive = require_position.__toESM(__formily_reactive);
52
30
  let sonner = require("sonner");
53
- sonner = __toESM(sonner);
31
+ sonner = require_position.__toESM(sonner);
54
32
  let __tanstack_react_query = require("@tanstack/react-query");
55
- __tanstack_react_query = __toESM(__tanstack_react_query);
33
+ __tanstack_react_query = require_position.__toESM(__tanstack_react_query);
56
34
 
57
35
  //#region src/lib/utils.ts
58
36
  function cn(...inputs) {
@@ -1034,6 +1012,11 @@ function useReadableFilters(columns, options = {}) {
1034
1012
  filtersRef.current = initial;
1035
1013
  return initial;
1036
1014
  });
1015
+ react.useEffect(() => {
1016
+ const next = parseReadableFilters(getUrlParams(), columnSnapshot);
1017
+ filtersRef.current = next;
1018
+ setFilters((previous) => JSON.stringify(previous) === JSON.stringify(next) ? previous : next);
1019
+ }, [columnSnapshot]);
1037
1020
  react.useEffect(() => {
1038
1021
  const handleUrlChange = () => {
1039
1022
  if (lastWrittenUrlRef.current !== null && window.location.search === lastWrittenUrlRef.current) {
@@ -4112,7 +4095,7 @@ function AutoTableActionBar({ table, onDeleteSelected, onUpdateSelected, batchUp
4112
4095
  { type: "export" },
4113
4096
  { type: "delete" }
4114
4097
  ]) : actions;
4115
- const resolvedActions = configuredActions?.filter((action$1) => !action$1.hidden);
4098
+ let resolvedActions = configuredActions?.filter((action$1) => !action$1.hidden);
4116
4099
  if (configuredActions === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
4117
4100
  renderBuiltinAction({ type: "batchUpdate" }),
4118
4101
  extraActions,
@@ -4120,7 +4103,20 @@ function AutoTableActionBar({ table, onDeleteSelected, onUpdateSelected, batchUp
4120
4103
  renderBuiltinAction({ type: "delete" })
4121
4104
  ] });
4122
4105
  if (!resolvedActions || resolvedActions.length === 0) return null;
4123
- if (!resolvedActions.some((action$1) => action$1.type !== "custom")) {
4106
+ let hasBuiltin = resolvedActions.some((action$1) => action$1.type !== "custom");
4107
+ if (resolvedActions.some((action$1) => "position" in action$1 && typeof action$1.position === "object")) if (!hasBuiltin) {
4108
+ resolvedActions = require_position.positionActions([
4109
+ { type: "batchUpdate" },
4110
+ ...extraActions ? [{
4111
+ type: "custom",
4112
+ component: extraActions
4113
+ }] : [],
4114
+ ...showDefaultExport ? [{ type: "export" }] : [],
4115
+ { type: "delete" }
4116
+ ], resolvedActions);
4117
+ hasBuiltin = true;
4118
+ } else resolvedActions = require_position.positionActions(resolvedActions);
4119
+ if (!hasBuiltin) {
4124
4120
  const startNodes = resolvedActions.filter(isBatchCustomAction).filter((action$1) => action$1.position === "start").map((action$1, index$1) => renderCustomAction(action$1, index$1));
4125
4121
  const endNodes = resolvedActions.filter(isBatchCustomAction).filter((action$1) => action$1.position !== "start").map((action$1, index$1) => renderCustomAction(action$1, index$1));
4126
4122
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
@@ -4423,7 +4419,7 @@ const filterModeConfig = {
4423
4419
  tooltip: "Linear-style command filters"
4424
4420
  }
4425
4421
  };
4426
- function AutoTable({ schema, data, pageCount = 1, pagination, total, overrides, classNames, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode, search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, deleteConfirmation, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
4422
+ function AutoTable({ schema, data, pageCount = 1, pagination, total, overrides, classNames, enableRowSelection = true, exclude, filterOnly, actions, pinnedColumns, filterMode, search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, deleteConfirmation, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
4427
4423
  const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
4428
4424
  const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
4429
4425
  const showToggle = modes.length > 1;
@@ -4438,9 +4434,24 @@ function AutoTable({ schema, data, pageCount = 1, pagination, total, overrides,
4438
4434
  const searchConfig = search && typeof search === "object" ? search : {};
4439
4435
  const enableAdvancedFilter = true;
4440
4436
  const columns = (0, react.useMemo)(() => {
4437
+ const columnOverrides = Object.assign({}, overrides);
4438
+ for (const key of filterOnly ?? []) {
4439
+ const field = key;
4440
+ Object.assign(columnOverrides, { [field]: {
4441
+ ...columnOverrides[field],
4442
+ hidden: false
4443
+ } });
4444
+ }
4441
4445
  const dataColumns = createTableSchema(schema, {
4442
- overrides,
4446
+ overrides: columnOverrides,
4443
4447
  exclude
4448
+ }).map((column) => {
4449
+ const key = column.id ?? ("accessorKey" in column ? String(column.accessorKey) : "");
4450
+ return filterOnly?.includes(key) ? {
4451
+ ...column,
4452
+ enableHiding: false,
4453
+ enableSorting: false
4454
+ } : column;
4444
4455
  });
4445
4456
  const result = enableRowSelection ? [createSelectColumn(), ...dataColumns] : dataColumns;
4446
4457
  if (actions) result.push(createActionsColumn(actions));
@@ -4450,7 +4461,8 @@ function AutoTable({ schema, data, pageCount = 1, pagination, total, overrides,
4450
4461
  overrides,
4451
4462
  enableRowSelection,
4452
4463
  exclude,
4453
- actions
4464
+ actions,
4465
+ filterOnly
4454
4466
  ]);
4455
4467
  const stableInitialState = (0, react.useMemo)(() => ({
4456
4468
  sorting: initialSorting,
@@ -4474,6 +4486,16 @@ function AutoTable({ schema, data, pageCount = 1, pagination, total, overrides,
4474
4486
  shallow: false,
4475
4487
  clearOnDefault: true
4476
4488
  });
4489
+ (0, react.useEffect)(() => {
4490
+ if (!filterOnly?.length) return;
4491
+ table.setColumnVisibility((previous) => {
4492
+ if (filterOnly.every((key) => previous[key] === false)) return previous;
4493
+ return {
4494
+ ...previous,
4495
+ ...Object.fromEntries(filterOnly.map((key) => [key, false]))
4496
+ };
4497
+ });
4498
+ }, [table, filterOnly]);
4477
4499
  const rowSelection = table.getState().rowSelection;
4478
4500
  const columnFilters = table.getState().columnFilters;
4479
4501
  const selectedRows = (0, react.useMemo)(() => table.getFilteredSelectedRowModel().rows.map((row) => row.original), [
@@ -4914,6 +4936,30 @@ function normalizeHasMore(result) {
4914
4936
 
4915
4937
  //#endregion
4916
4938
  //#region src/lib/field-config.ts
4939
+ function mergeFieldPart(base, override) {
4940
+ if (override === void 0) return base;
4941
+ if (override === false || base === false || typeof base !== "object" || typeof override !== "object" || base === null || override === null || Array.isArray(base) || Array.isArray(override)) return override;
4942
+ return {
4943
+ ...base,
4944
+ ...override
4945
+ };
4946
+ }
4947
+ function mergeFieldConfig(base, override) {
4948
+ return {
4949
+ ...base,
4950
+ ...override,
4951
+ enum: override?.enum ?? base?.enum,
4952
+ dataSource: override?.dataSource ?? base?.dataSource,
4953
+ table: mergeFieldPart(base?.table, override?.table),
4954
+ filter: mergeFieldPart(base?.filter, override?.filter),
4955
+ form: mergeFieldPart(base?.form, override?.form)
4956
+ };
4957
+ }
4958
+ function mergeFields(base, override) {
4959
+ if (!base && !override) return void 0;
4960
+ const keys = new Set([...Object.keys(base ?? {}), ...Object.keys(override ?? {})]);
4961
+ return Object.fromEntries(Array.from(keys).map((key) => [key, mergeFieldConfig(base?.[key], override?.[key])]));
4962
+ }
4917
4963
  function normalizeFieldOptions$1(options) {
4918
4964
  if (!options || options.length === 0) return void 0;
4919
4965
  return options.map((option) => ({
@@ -6273,15 +6319,18 @@ function unregisterOwnerActions(ownerId, options = {}, shouldNotify = true) {
6273
6319
  if (changed && shouldNotify) notify();
6274
6320
  }
6275
6321
  function sortEntries(left, right) {
6276
- const orderDiff = left.order - right.order;
6322
+ const orderDiff = require_position.compareOrder(left, right);
6277
6323
  if (orderDiff !== 0) return orderDiff;
6278
6324
  const ownerDiff = left.ownerId.localeCompare(right.ownerId);
6279
6325
  if (ownerDiff !== 0) return ownerDiff;
6280
6326
  return left.seq - right.seq;
6281
6327
  }
6282
6328
  function withoutRegistryMeta(action$1) {
6283
- const { id, order,...rest } = action$1;
6284
- return rest;
6329
+ const { id, order, position,...rest } = action$1;
6330
+ return {
6331
+ ...rest,
6332
+ ...typeof position === "string" ? { position } : {}
6333
+ };
6285
6334
  }
6286
6335
  function isCustomAction$1(action$1) {
6287
6336
  return action$1.type === "custom";
@@ -6296,12 +6345,10 @@ function resolveActions$1(targetId, zone, ownerActions) {
6296
6345
  if (isCustomAction$1(action$1) && action$1.id && !isMaskedCustom(action$1)) customOverrides.set(action$1.id, entry);
6297
6346
  }
6298
6347
  const ownerCustomIds = new Set(ownerActions.flatMap((action$1) => isCustomAction$1(action$1) && action$1.id ? [action$1.id] : []));
6299
- const baseActions = ownerActions.filter((action$1) => !action$1.hidden && !isMaskedCustom(action$1)).map((action$1) => withoutRegistryMeta(isCustomAction$1(action$1) && action$1.id ? customOverrides.get(action$1.id)?.action ?? action$1 : action$1));
6348
+ const baseActions = ownerActions.filter((action$1) => !action$1.hidden && !isMaskedCustom(action$1)).map((action$1) => ({ ...isCustomAction$1(action$1) && action$1.id ? customOverrides.get(action$1.id)?.action ?? action$1 : action$1 }));
6300
6349
  const isReplacedCustom = ({ action: action$1, seq: seq$1 }) => isCustomAction$1(action$1) && Boolean(action$1.id && (ownerCustomIds.has(action$1.id) || customOverrides.get(action$1.id)?.seq !== seq$1));
6301
- if (registered.length === 0) return baseActions;
6302
6350
  const nextActions = [...baseActions];
6303
- const startCustomActions = [];
6304
- const endCustomActions = [];
6351
+ const extraActions = [];
6305
6352
  const groups = /* @__PURE__ */ new Map();
6306
6353
  for (const entry of registered) {
6307
6354
  if (isMaskedCustom(entry.action)) continue;
@@ -6315,7 +6362,7 @@ function resolveActions$1(targetId, zone, ownerActions) {
6315
6362
  if (existingIndex >= 0) nextActions.splice(existingIndex, 1);
6316
6363
  continue;
6317
6364
  }
6318
- const builtin = withoutRegistryMeta(action$1);
6365
+ const builtin = action$1;
6319
6366
  if (existingIndex >= 0) nextActions[existingIndex] = {
6320
6367
  ...nextActions[existingIndex],
6321
6368
  ...builtin
@@ -6326,7 +6373,13 @@ function resolveActions$1(targetId, zone, ownerActions) {
6326
6373
  const items = group.sort((left, right) => left.seq - right.seq).flatMap((entry) => {
6327
6374
  const { action: action$1 } = entry;
6328
6375
  if (action$1.hidden || isReplacedCustom(entry)) return [];
6329
- if (isCustomAction$1(action$1)) return [withoutRegistryMeta(action$1)];
6376
+ if (isCustomAction$1(action$1)) {
6377
+ if (action$1.before) {
6378
+ extraActions.push({ ...action$1 });
6379
+ return [];
6380
+ }
6381
+ return [{ ...action$1 }];
6382
+ }
6330
6383
  const builtin = nextActions.find((item) => item.type === action$1.type);
6331
6384
  return builtin ? [builtin] : [];
6332
6385
  });
@@ -6345,13 +6398,18 @@ function resolveActions$1(targetId, zone, ownerActions) {
6345
6398
  cursor += 1;
6346
6399
  }
6347
6400
  }
6348
- } else for (const custom of items) (custom.position === "start" ? startCustomActions : endCustomActions).push(custom);
6401
+ } else extraActions.push(...items);
6349
6402
  }
6350
- return [
6351
- ...startCustomActions,
6352
- ...nextActions,
6353
- ...endCustomActions
6354
- ];
6403
+ for (const action$1 of [...nextActions, ...extraActions]) {
6404
+ if (!isCustomAction$1(action$1) || !action$1.before) continue;
6405
+ const anchor = nextActions.find((item) => !isCustomAction$1(item) && item.type === action$1.before);
6406
+ if (anchor) action$1.position = {
6407
+ anchor: anchor.id ?? anchor.type,
6408
+ side: "before"
6409
+ };
6410
+ else if (typeof action$1.position === "object") action$1.position = "end";
6411
+ }
6412
+ return require_position.positionActions(nextActions, extraActions).map(withoutRegistryMeta);
6355
6413
  }
6356
6414
  const crudActions = {
6357
6415
  register(registration) {
@@ -6453,8 +6511,8 @@ function resolveOwnerActions(config, defaults) {
6453
6511
  const items = resolved !== void 0 && resolved.length > 0 ? [...resolved] : [];
6454
6512
  if (items.length === 0) return [...defaults];
6455
6513
  if (items.some((item) => !isCustomAction(item))) return items;
6456
- const startItems = items.filter((item) => isCustomAction(item) && item.position === "start");
6457
- const endItems = items.filter((item) => isCustomAction(item) && item.position !== "start");
6514
+ const startItems = items.filter((item) => isCustomAction(item) && require_position.matchesPosition(item.position, "start"));
6515
+ const endItems = items.filter((item) => isCustomAction(item) && !require_position.matchesPosition(item.position, "start"));
6458
6516
  return [
6459
6517
  ...startItems,
6460
6518
  ...defaults,
@@ -6500,30 +6558,6 @@ function resolveToolbarActionsWithResolver(targetId, ownerActions, context) {
6500
6558
  const resolver = autoCrudToolbarResolver;
6501
6559
  return targetId !== void 0 && targetId.length > 0 && resolver !== null ? resolver(targetId, ownerActions, context) : ownerActions;
6502
6560
  }
6503
- function mergeFieldPart(base, override) {
6504
- if (override === void 0) return base;
6505
- if (override === false || base === false || typeof base !== "object" || typeof override !== "object" || base === null || override === null || Array.isArray(base) || Array.isArray(override)) return override;
6506
- return {
6507
- ...base,
6508
- ...override
6509
- };
6510
- }
6511
- function mergeFieldConfig(base, override) {
6512
- return {
6513
- ...base,
6514
- ...override,
6515
- enum: override?.enum ?? base?.enum,
6516
- dataSource: override?.dataSource ?? base?.dataSource,
6517
- table: mergeFieldPart(base?.table, override?.table),
6518
- filter: mergeFieldPart(base?.filter, override?.filter),
6519
- form: mergeFieldPart(base?.form, override?.form)
6520
- };
6521
- }
6522
- function mergeFields(base, override) {
6523
- if (!base && !override) return void 0;
6524
- const keys = new Set([...Object.keys(base ?? {}), ...Object.keys(override ?? {})]);
6525
- return Object.fromEntries(Array.from(keys).map((key) => [key, mergeFieldConfig(base?.[key], override?.[key])]));
6526
- }
6527
6561
  function applyResourceTablePresentation(fields, resourceFields) {
6528
6562
  if (!fields || !resourceFields) return fields;
6529
6563
  return Object.fromEntries(Object.entries(fields).map(([key, config]) => {
@@ -7425,6 +7459,12 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
7425
7459
  const [exporting, setExporting] = react.useState(false);
7426
7460
  const getSelectedRowsRef = react.useRef(null);
7427
7461
  const dynamicFilterOptions = useDynamicFilterOptions(resolvedFields);
7462
+ const filterOnly = react.useMemo(() => Object.entries(resolvedFields).filter(([key, config]) => config.table === false && config.filter && config.hidden !== true && !denyFields?.includes(key) && !tableConfig?.hidden?.includes(key) && tableConfig?.overrides?.[key]?.hidden !== true).map(([key]) => key), [
7463
+ resolvedFields,
7464
+ denyFields,
7465
+ tableConfig?.hidden,
7466
+ tableConfig?.overrides
7467
+ ]);
7428
7468
  const hiddenColumns = react.useMemo(() => buildHiddenColumns(resolvedFields, tableConfig?.hidden, denyFields, tableConfig?.overrides), [
7429
7469
  resolvedFields,
7430
7470
  tableConfig?.hidden,
@@ -7775,7 +7815,8 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
7775
7815
  ...resource.tableData.total !== void 0 ? { total: resource.tableData.total } : {},
7776
7816
  overrides: tableOverrides,
7777
7817
  classNames: tableConfig?.classNames,
7778
- exclude: hiddenColumns,
7818
+ exclude: hiddenColumns.filter((key) => !filterOnly.includes(key)),
7819
+ filterOnly,
7779
7820
  filterMode: tableConfig?.filterModes,
7780
7821
  search: searchConfig,
7781
7822
  actions: tableRowActions,
@@ -8608,7 +8649,7 @@ function modalReducer(state, action$1) {
8608
8649
  /**
8609
8650
  * Hook 主函数
8610
8651
  */
8611
- function useAutoCrudResource({ router, schema, query: queryTransform, options = {} }) {
8652
+ function useAutoCrudResource({ router, schema, query: queryTransform, fields, options = {} }) {
8612
8653
  const { idKey = "id", defaultVariant = "dialog", hooks, toast: toastAdapter, exportFetcher, defaultSort: defaultSortOption } = options;
8613
8654
  const toast = (0, react.useMemo)(() => toastAdapter === false ? noopToastAdapter : toastAdapter ?? defaultToastAdapter, [toastAdapter]);
8614
8655
  const hooksRef = (0, react.useRef)(hooks);
@@ -8620,7 +8661,14 @@ function useAutoCrudResource({ router, schema, query: queryTransform, options =
8620
8661
  const defaultSorting = (0, react.useMemo)(() => defaultSortOption === false ? [] : defaultSortOption ?? getDefaultSortingForSchema(resolvedSchema), [defaultSortOption, resolvedSchema]);
8621
8662
  const metadataFields = (0, react.useMemo)(() => readMetadataFields(metadata?.fields), [metadata?.fields]);
8622
8663
  const capabilities = metadata?.capabilities;
8623
- const columns = (0, react.useMemo)(() => createTableSchema(resolvedSchema), [resolvedSchema]);
8664
+ const columns = (0, react.useMemo)(() => createTableSchema(resolvedSchema, { overrides: Object.fromEntries(Object.entries(mergeFields(metadataFields, fields) ?? {}).flatMap(([key, field]) => {
8665
+ const filter = field.filter;
8666
+ return filter && typeof filter === "object" && filter.variant ? [[key, { meta: { variant: filter.variant } }]] : [];
8667
+ })) }), [
8668
+ resolvedSchema,
8669
+ fields,
8670
+ metadataFields
8671
+ ]);
8624
8672
  const [urlParams] = useQueryStates({
8625
8673
  page: parseAsInteger.withDefault(1),
8626
8674
  perPage: parseAsInteger.withDefault(10),
@@ -9275,8 +9323,10 @@ Object.defineProperty(exports, 'Select', {
9275
9323
  return __wordrhyme_shadcn_ui.Select;
9276
9324
  }
9277
9325
  });
9326
+ exports.actionPositionSchema = require_position.actionPositionSchema;
9278
9327
  exports.cn = cn;
9279
9328
  exports.coerceRowValues = coerceRowValues;
9329
+ exports.compareOrder = require_position.compareOrder;
9280
9330
  exports.components = components;
9281
9331
  exports.createActionsColumn = createActionsColumn;
9282
9332
  exports.createEditFormSchema = createEditFormSchema;
@@ -9302,6 +9352,7 @@ exports.getUrlParams = getUrlParams;
9302
9352
  exports.humanize = humanize;
9303
9353
  exports.jaJP = jaJP;
9304
9354
  exports.koKR = koKR;
9355
+ exports.matchesPosition = require_position.matchesPosition;
9305
9356
  exports.noopToastAdapter = noopToastAdapter;
9306
9357
  exports.normalizeDataSourceConfig = normalizeDataSourceConfig;
9307
9358
  exports.normalizeOptions = normalizeOptions;
@@ -9313,6 +9364,7 @@ exports.parseCSV = parseCSV;
9313
9364
  exports.parseImportFile = parseImportFile;
9314
9365
  exports.parseJSON = parseJSON;
9315
9366
  exports.parseZodField = parseZodField;
9367
+ exports.positionActions = require_position.positionActions;
9316
9368
  exports.resolveLocale = resolveLocale;
9317
9369
  exports.setDateFormatter = setDateFormatter;
9318
9370
  exports.setSearchParams = setSearchParams;