@wordrhyme/auto-crud 1.6.0 → 1.7.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
@@ -39,6 +39,8 @@ let nanoid = require("nanoid");
39
39
  nanoid = __toESM(nanoid);
40
40
  let __wordrhyme_shadcn_ui = require("@wordrhyme/shadcn-ui");
41
41
  __wordrhyme_shadcn_ui = __toESM(__wordrhyme_shadcn_ui);
42
+ let __wordrhyme_ui = require("@wordrhyme/ui");
43
+ __wordrhyme_ui = __toESM(__wordrhyme_ui);
42
44
  let zod = require("zod");
43
45
  zod = __toESM(zod);
44
46
  let __formily_core = require("@formily/core");
@@ -495,8 +497,14 @@ function formatDate(date, opts = {}, preset) {
495
497
 
496
498
  //#endregion
497
499
  //#region src/components/data-table/data-table.tsx
498
- function DataTable({ table, actionBar, children, className,...props }) {
500
+ function DataTable({ table, actionBar, children, className, classNames,...props }) {
499
501
  useDateFormatterVersion();
502
+ const columns = [
503
+ ...table.getLeftVisibleLeafColumns(),
504
+ ...table.getCenterVisibleLeafColumns(),
505
+ ...table.getRightVisibleLeafColumns()
506
+ ];
507
+ const hasWidthCap = columns.some((column) => (column.columnDef.maxSize ?? Number.MAX_SAFE_INTEGER) < Number.MAX_SAFE_INTEGER);
500
508
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
501
509
  className: cn("flex w-full flex-col gap-2.5 overflow-auto", className),
502
510
  ...props,
@@ -504,21 +512,53 @@ function DataTable({ table, actionBar, children, className,...props }) {
504
512
  children,
505
513
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
506
514
  className: "overflow-hidden rounded-md border",
507
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Table, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableRow, { children: headerGroup.headers.map((header) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableHead, {
508
- colSpan: header.colSpan,
509
- style: { ...getColumnPinningStyle({ column: header.column }) },
510
- children: header.isPlaceholder ? null : (0, __tanstack_react_table.flexRender)(header.column.columnDef.header, header.getContext())
511
- }, header.id)) }, headerGroup.id)) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableBody, { children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableRow, {
512
- "data-state": row.getIsSelected() && "selected",
513
- children: row.getVisibleCells().map((cell) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableCell, {
514
- style: { ...getColumnPinningStyle({ column: cell.column }) },
515
- children: (0, __tanstack_react_table.flexRender)(cell.column.columnDef.cell, cell.getContext())
516
- }, cell.id))
517
- }, row.id)) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableRow, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableCell, {
518
- colSpan: table.getAllColumns().length,
519
- className: "h-24 text-center",
520
- children: "No results."
521
- }) }) })] })
515
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Table, {
516
+ className: classNames?.table,
517
+ style: hasWidthCap ? {
518
+ tableLayout: "fixed",
519
+ width: columns.reduce((width, column) => width + column.getSize(), 0)
520
+ } : void 0,
521
+ children: [
522
+ hasWidthCap && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("colgroup", { children: columns.map((column) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("col", { style: { width: column.getSize() } }, column.id)) }),
523
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableHeader, {
524
+ className: classNames?.thead,
525
+ children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableRow, {
526
+ className: classNames?.tr,
527
+ children: headerGroup.headers.map((header) => {
528
+ const columnClassName = header.column.columnDef.meta?.classNames?.th;
529
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableHead, {
530
+ colSpan: header.colSpan,
531
+ className: cn(hasWidthCap && "overflow-hidden text-ellipsis", classNames?.th, typeof columnClassName === "string" ? columnClassName : void 0),
532
+ style: { ...getColumnPinningStyle({ column: header.column }) },
533
+ children: header.isPlaceholder ? null : (0, __tanstack_react_table.flexRender)(header.column.columnDef.header, header.getContext())
534
+ }, header.id);
535
+ })
536
+ }, headerGroup.id))
537
+ }),
538
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableBody, {
539
+ className: classNames?.tbody,
540
+ children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableRow, {
541
+ className: classNames?.tr,
542
+ "data-state": row.getIsSelected() && "selected",
543
+ children: row.getVisibleCells().map((cell) => {
544
+ const columnClassName = cell.column.columnDef.meta?.classNames?.td;
545
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableCell, {
546
+ className: cn(hasWidthCap && "overflow-hidden text-ellipsis", classNames?.td, typeof columnClassName === "string" ? columnClassName : void 0),
547
+ style: { ...getColumnPinningStyle({ column: cell.column }) },
548
+ children: (0, __tanstack_react_table.flexRender)(cell.column.columnDef.cell, cell.getContext())
549
+ }, cell.id);
550
+ })
551
+ }, row.id)) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableRow, {
552
+ className: classNames?.tr,
553
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.TableCell, {
554
+ colSpan: table.getAllColumns().length,
555
+ className: cn("h-24 text-center", classNames?.td),
556
+ children: "No results."
557
+ })
558
+ })
559
+ })
560
+ ]
561
+ })
522
562
  }),
523
563
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
524
564
  className: "flex flex-col gap-2.5",
@@ -3412,10 +3452,7 @@ function renderCell(value, type, options) {
3412
3452
  className: "tabular-nums",
3413
3453
  children: String(value)
3414
3454
  });
3415
- default: return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3416
- className: "truncate max-w-48",
3417
- children: String(value)
3418
- });
3455
+ default: return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: String(value) });
3419
3456
  }
3420
3457
  }
3421
3458
  /**
@@ -3501,33 +3538,38 @@ function createSelectColumn() {
3501
3538
  size: 40
3502
3539
  };
3503
3540
  }
3541
+ function ActionsCell({ row, column }) {
3542
+ const items = column.columnDef.meta?.rowActions ?? [];
3543
+ const renderActionComponent = (item) => {
3544
+ if (!item.component) return null;
3545
+ return typeof item.component === "function" ? item.component(item.getContext?.(row.original)) : item.component;
3546
+ };
3547
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.DropdownMenu, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.DropdownMenuTrigger, {
3548
+ asChild: true,
3549
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Button, {
3550
+ "aria-label": "Open menu",
3551
+ variant: "ghost",
3552
+ className: "flex size-8 p-0 data-[state=open]:bg-muted",
3553
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Ellipsis, { className: "size-4" })
3554
+ })
3555
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.DropdownMenuContent, {
3556
+ align: "end",
3557
+ className: "w-40",
3558
+ children: items.map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [item.separator && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.DropdownMenuSeparator, {}), item.component ? renderActionComponent(item) : item.label && item.onClick ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.DropdownMenuItem, {
3559
+ className: item.variant === "destructive" ? "text-destructive" : "",
3560
+ onClick: () => item.onClick?.(row.original),
3561
+ children: item.label
3562
+ }) : null] }, i))
3563
+ })] });
3564
+ }
3504
3565
  /**
3505
3566
  * 创建操作列
3506
3567
  */
3507
3568
  function createActionsColumn(items) {
3508
- const renderActionComponent = (item, row) => {
3509
- if (!item.component) return null;
3510
- return typeof item.component === "function" ? item.component(item.getContext?.(row.original)) : item.component;
3511
- };
3512
3569
  return {
3513
3570
  id: "actions",
3514
- cell: ({ row }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.DropdownMenu, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.DropdownMenuTrigger, {
3515
- asChild: true,
3516
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Button, {
3517
- "aria-label": "Open menu",
3518
- variant: "ghost",
3519
- className: "flex size-8 p-0 data-[state=open]:bg-muted",
3520
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Ellipsis, { className: "size-4" })
3521
- })
3522
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.DropdownMenuContent, {
3523
- align: "end",
3524
- className: "w-40",
3525
- children: items.map((item, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [item.separator && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.DropdownMenuSeparator, {}), item.component ? renderActionComponent(item, row) : item.label && item.onClick ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.DropdownMenuItem, {
3526
- className: item.variant === "destructive" ? "text-destructive" : "",
3527
- onClick: () => item.onClick?.(row.original),
3528
- children: item.label
3529
- }) : null] }, i))
3530
- })] }),
3571
+ cell: ActionsCell,
3572
+ meta: { rowActions: items },
3531
3573
  size: 40
3532
3574
  };
3533
3575
  }
@@ -4206,7 +4248,7 @@ const filterModeConfig = {
4206
4248
  tooltip: "Linear-style command filters"
4207
4249
  }
4208
4250
  };
4209
- function AutoTable({ schema, data, pageCount = 1, total, overrides, enableRowSelection = true, exclude, actions, pinnedColumns, filterMode, search = false, onDeleteSelected, onUpdateSelected, batchUpdateFields, actionBarExtra, actionBarActions, deleteConfirmation, initialSorting, enableExport = true, showDefaultExport = true, onSelectedCountChange, onSelectedRowsChange, getSelectedRows }) {
4251
+ function AutoTable({ schema, data, pageCount = 1, 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 }) {
4210
4252
  const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
4211
4253
  const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
4212
4254
  const showToggle = modes.length > 1;
@@ -4368,7 +4410,10 @@ function AutoTable({ schema, data, pageCount = 1, total, overrides, enableRowSel
4368
4410
  ]
4369
4411
  })]
4370
4412
  }),
4371
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, { table }),
4413
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, {
4414
+ table,
4415
+ classNames
4416
+ }),
4372
4417
  enableRowSelection && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoTableActionBar, {
4373
4418
  table,
4374
4419
  onDeleteSelected,
@@ -4388,16 +4433,16 @@ function AutoTable({ schema, data, pageCount = 1, total, overrides, enableRowSel
4388
4433
  //#endregion
4389
4434
  //#region src/components/auto-crud/form-modal.tsx
4390
4435
  function FormModal({ open, onOpenChange, title, description, children, variant = "dialog", side = "right", className, footer }) {
4391
- if (variant === "sheet") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Sheet, {
4436
+ if (variant === "sheet") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.Sheet, {
4392
4437
  open,
4393
4438
  onOpenChange,
4394
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.SheetContent, {
4439
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.SheetContent, {
4395
4440
  side,
4396
4441
  className: cn("sm:max-w-lg flex flex-col p-0", className),
4397
4442
  children: [
4398
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.SheetHeader, {
4443
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.SheetHeader, {
4399
4444
  className: "flex-shrink-0 px-6 pt-6",
4400
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.SheetTitle, { children: title }), description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.SheetDescription, { children: description })]
4445
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.SheetTitle, { children: title }), description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.SheetDescription, { children: description })]
4401
4446
  }),
4402
4447
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4403
4448
  className: "flex-1 overflow-y-auto min-h-0",
@@ -4413,15 +4458,15 @@ function FormModal({ open, onOpenChange, title, description, children, variant =
4413
4458
  ]
4414
4459
  })
4415
4460
  });
4416
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Dialog, {
4461
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.Dialog, {
4417
4462
  open,
4418
4463
  onOpenChange,
4419
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.DialogContent, {
4464
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.DialogContent, {
4420
4465
  className: cn("max-w-2xl sm:max-w-2xl flex flex-col max-h-[85vh] overflow-hidden p-0", className),
4421
4466
  children: [
4422
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.DialogHeader, {
4467
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_ui.DialogHeader, {
4423
4468
  className: "flex-shrink-0 px-6 pt-6",
4424
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.DialogTitle, { children: title }), description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.DialogDescription, { children: description })]
4469
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.DialogTitle, { children: title }), description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_ui.DialogDescription, { children: description })]
4425
4470
  }),
4426
4471
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4427
4472
  className: "flex-1 overflow-y-auto min-h-0",
@@ -5597,6 +5642,31 @@ function CrudFormModal({ open, onOpenChange, mode, schema, initialValues, onSubm
5597
5642
  });
5598
5643
  }
5599
5644
 
5645
+ //#endregion
5646
+ //#region src/lib/row-action-dialog.tsx
5647
+ /** Keep custom dialogs at table level, independently of the source row's lifetime. */
5648
+ function useRowActionDialog() {
5649
+ const [dialog, setDialog] = react.useState(null);
5650
+ const session = react.useRef(0);
5651
+ return {
5652
+ openComponent: react.useCallback((next) => {
5653
+ const id = ++session.current;
5654
+ const dismiss = () => {
5655
+ if (session.current === id) setDialog(null);
5656
+ };
5657
+ setDialog(react.cloneElement(next, {
5658
+ key: id,
5659
+ open: true,
5660
+ onOpenChange: (open) => {
5661
+ if (!open) dismiss();
5662
+ },
5663
+ onDismiss: dismiss
5664
+ }));
5665
+ }, []),
5666
+ dialog
5667
+ };
5668
+ }
5669
+
5600
5670
  //#endregion
5601
5671
  //#region src/components/auto-crud/import-dialog.tsx
5602
5672
  function ImportDialog({ open, onOpenChange, onImport, columns = [], title, locale = zhCN.importDialog }) {
@@ -5953,22 +6023,29 @@ function isCustomAction$1(action$1) {
5953
6023
  return action$1.type === "custom";
5954
6024
  }
5955
6025
  function resolveActions$1(targetId, zone, ownerActions) {
5956
- const baseActions = ownerActions.filter((action$1) => !action$1.hidden).map((action$1) => withoutRegistryMeta(action$1));
5957
- if (!targetId) return baseActions;
5958
- const registered = crudActions.get(targetId, zone);
6026
+ const registered = targetId ? crudActions.get(targetId, zone) : [];
6027
+ const hiddenCustomIds = new Set(registered.flatMap(({ action: action$1 }) => isCustomAction$1(action$1) && action$1.hidden && action$1.id ? [action$1.id] : []));
6028
+ const isMaskedCustom = (action$1) => isCustomAction$1(action$1) && Boolean(action$1.id && hiddenCustomIds.has(action$1.id));
6029
+ const customOverrides = /* @__PURE__ */ new Map();
6030
+ for (const entry of registered) {
6031
+ const { action: action$1 } = entry;
6032
+ if (isCustomAction$1(action$1) && action$1.id && !isMaskedCustom(action$1)) customOverrides.set(action$1.id, entry);
6033
+ }
6034
+ const ownerCustomIds = new Set(ownerActions.flatMap((action$1) => isCustomAction$1(action$1) && action$1.id ? [action$1.id] : []));
6035
+ 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));
6036
+ 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));
5959
6037
  if (registered.length === 0) return baseActions;
5960
6038
  const nextActions = [...baseActions];
5961
6039
  const startCustomActions = [];
5962
6040
  const endCustomActions = [];
6041
+ const groups = /* @__PURE__ */ new Map();
5963
6042
  for (const entry of registered) {
6043
+ if (isMaskedCustom(entry.action)) continue;
6044
+ const group = groups.get(entry.ownerId) ?? [];
6045
+ group.push(entry);
6046
+ groups.set(entry.ownerId, group);
5964
6047
  const action$1 = entry.action;
5965
- if (action$1.hidden && isCustomAction$1(action$1)) continue;
5966
- if (isCustomAction$1(action$1)) {
5967
- const custom = withoutRegistryMeta(action$1);
5968
- if (custom.position === "start") startCustomActions.push(custom);
5969
- else endCustomActions.push(custom);
5970
- continue;
5971
- }
6048
+ if (isCustomAction$1(action$1)) continue;
5972
6049
  const existingIndex = nextActions.findIndex((item) => item.type === action$1.type);
5973
6050
  if (action$1.hidden) {
5974
6051
  if (existingIndex >= 0) nextActions.splice(existingIndex, 1);
@@ -5981,6 +6058,31 @@ function resolveActions$1(targetId, zone, ownerActions) {
5981
6058
  };
5982
6059
  else nextActions.push(builtin);
5983
6060
  }
6061
+ for (const group of groups.values()) {
6062
+ const items = group.sort((left, right) => left.seq - right.seq).flatMap((entry) => {
6063
+ const { action: action$1 } = entry;
6064
+ if (action$1.hidden || isReplacedCustom(entry)) return [];
6065
+ if (isCustomAction$1(action$1)) return [withoutRegistryMeta(action$1)];
6066
+ const builtin = nextActions.find((item) => item.type === action$1.type);
6067
+ return builtin ? [builtin] : [];
6068
+ });
6069
+ const firstBuiltin = items.find((item) => !isCustomAction$1(item));
6070
+ if (firstBuiltin) {
6071
+ let cursor = nextActions.indexOf(firstBuiltin);
6072
+ for (const item of items) {
6073
+ const existing = nextActions.indexOf(item);
6074
+ if (existing >= cursor) cursor = existing + 1;
6075
+ else {
6076
+ if (existing >= 0) {
6077
+ nextActions.splice(existing, 1);
6078
+ cursor -= 1;
6079
+ }
6080
+ nextActions.splice(cursor, 0, item);
6081
+ cursor += 1;
6082
+ }
6083
+ }
6084
+ } else for (const custom of items) (custom.position === "start" ? startCustomActions : endCustomActions).push(custom);
6085
+ }
5984
6086
  return [
5985
6087
  ...startCustomActions,
5986
6088
  ...nextActions,
@@ -6609,6 +6711,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
6609
6711
  const mergedSharedDynamicOptions = mergeFieldOptions(dynamicFilterLabelOptions, tableConfig?.dataSource ? void 0 : dynamicResolveOptions);
6610
6712
  const dynamicOptions = !fieldOptions && mergedSharedDynamicOptions ? toTableOptions(mergedSharedDynamicOptions) : void 0;
6611
6713
  const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
6714
+ const tableClassNames = tableConfig?.classNames;
6612
6715
  const fieldEnumMeta = tableOptions ? {
6613
6716
  options: tableOptions,
6614
6717
  variant: "multiSelect"
@@ -6648,13 +6751,14 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
6648
6751
  enableColumnFilter: false
6649
6752
  };
6650
6753
  }
6651
- if (fieldEnumMeta || fieldDataSourceMeta || tableMeta || filterMeta) result[key] = {
6754
+ if (fieldEnumMeta || fieldDataSourceMeta || tableMeta || tableClassNames !== void 0 || filterMeta) result[key] = {
6652
6755
  ...result[key],
6653
6756
  meta: {
6654
6757
  ...result[key]?.meta ?? {},
6655
6758
  ...fieldEnumMeta ?? {},
6656
6759
  ...fieldDataSourceMeta ?? {},
6657
6760
  ...tableMeta ?? {},
6761
+ ...tableClassNames !== void 0 ? { classNames: tableClassNames } : {},
6658
6762
  ...filterMeta ?? {}
6659
6763
  }
6660
6764
  };
@@ -6672,6 +6776,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
6672
6776
  };
6673
6777
  else if (config.table && typeof config.table === "object") {
6674
6778
  const { meta, display,...tableProps } = config.table;
6779
+ delete tableProps.classNames;
6675
6780
  delete tableProps.options;
6676
6781
  delete tableProps.dataSource;
6677
6782
  result[key] = {
@@ -6704,7 +6809,7 @@ function buildCapabilityTableOverrides(schema, capabilities) {
6704
6809
  const override = {};
6705
6810
  if (capabilities.filters) {
6706
6811
  if (!capabilities.filters.enabled) override.enableColumnFilter = false;
6707
- else if (filterSet) override.enableColumnFilter = filterSet.has(key);
6812
+ else if (filterSet && !filterSet.has(key)) override.enableColumnFilter = false;
6708
6813
  }
6709
6814
  if (capabilities.sort) {
6710
6815
  if (!capabilities.sort.enabled) override.enableSorting = false;
@@ -6828,6 +6933,21 @@ function renderFieldValue(value, type, booleanLocale, options, display = "auto",
6828
6933
  children: ["+", value.length - maxItems]
6829
6934
  })]
6830
6935
  });
6936
+ const tone = options.find((option) => option.value === String(value))?.badgeTone;
6937
+ const toneClassName = tone && {
6938
+ neutral: "border-border bg-muted text-muted-foreground",
6939
+ success: "border-emerald-200 bg-emerald-50 text-emerald-700 dark:border-emerald-800 dark:bg-emerald-950 dark:text-emerald-300",
6940
+ warning: "border-amber-200 bg-amber-50 text-amber-700 dark:border-amber-800 dark:bg-amber-950 dark:text-amber-300",
6941
+ info: "border-blue-200 bg-blue-50 text-blue-700 dark:border-blue-800 dark:bg-blue-950 dark:text-blue-300"
6942
+ }[tone];
6943
+ if (toneClassName) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__wordrhyme_shadcn.Badge, {
6944
+ variant: "outline",
6945
+ className: toneClassName,
6946
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6947
+ "aria-hidden": "true",
6948
+ className: "size-1.5 shrink-0 rounded-full bg-current"
6949
+ }), getOptionLabel(value, options)]
6950
+ });
6831
6951
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Badge, {
6832
6952
  variant: "outline",
6833
6953
  className: "capitalize",
@@ -6938,14 +7058,9 @@ function ViewModalContent({ open, onOpenChange, variant, data, schema, fields: f
6938
7058
  /**
6939
7059
  * 解析列表行操作
6940
7060
  */
6941
- function resolveActions(actionsOrFn, defaults, rowActionsLocale, context) {
6942
- const resolvedItems = typeof actionsOrFn === "function" ? actionsOrFn([
6943
- { type: "view" },
6944
- { type: "edit" },
6945
- { type: "copy" },
6946
- { type: "delete" }
6947
- ]) : actionsOrFn;
7061
+ function resolveActions(actions, defaults, rowActionsLocale, context) {
6948
7062
  const getContext = (row) => ({
7063
+ MenuItem: __wordrhyme_ui.DropdownMenuItem,
6949
7064
  crudId: context.crudId,
6950
7065
  idKey: context.idKey,
6951
7066
  row,
@@ -6953,54 +7068,13 @@ function resolveActions(actionsOrFn, defaults, rowActionsLocale, context) {
6953
7068
  openView: defaults.openView,
6954
7069
  ...defaults.openEdit ? { openEdit: defaults.openEdit } : {},
6955
7070
  ...defaults.copyRow ? { copyRow: defaults.copyRow } : {},
6956
- ...defaults.openDelete ? { openDelete: defaults.openDelete } : {}
7071
+ ...defaults.openDelete ? { openDelete: defaults.openDelete } : {},
7072
+ open: (options) => {
7073
+ if (options.type === "custom") context.openComponent(options.component);
7074
+ else handlerMap[options.type]?.(options.row);
7075
+ }
6957
7076
  });
6958
- const defaultItems = [
6959
- {
6960
- label: rowActionsLocale.view,
6961
- onClick: defaults.openView
6962
- },
6963
- ...defaults.openEdit ? [{
6964
- label: rowActionsLocale.edit,
6965
- onClick: defaults.openEdit
6966
- }] : [],
6967
- ...defaults.copyRow ? [{
6968
- label: rowActionsLocale.copy,
6969
- onClick: defaults.copyRow
6970
- }] : [],
6971
- ...defaults.openDelete ? [{
6972
- label: rowActionsLocale.delete,
6973
- onClick: defaults.openDelete,
6974
- separator: true,
6975
- variant: "destructive"
6976
- }] : []
6977
- ];
6978
- if (resolvedItems === void 0) return defaultItems;
6979
- const items = resolvedItems.filter((item) => !item.hidden);
6980
- if (items.length === 0) return [];
6981
- if (!items.some((i) => i.type !== "custom")) {
6982
- const startItems = items.filter((i) => i.type === "custom" && i.position === "start").map(({ label, onClick, component, separator, variant }) => ({
6983
- label,
6984
- onClick,
6985
- component,
6986
- getContext,
6987
- separator,
6988
- variant
6989
- }));
6990
- const endItems = items.filter((i) => i.type === "custom" && i.position !== "start").map(({ label, onClick, component, separator, variant }) => ({
6991
- label,
6992
- onClick,
6993
- component,
6994
- getContext,
6995
- separator,
6996
- variant
6997
- }));
6998
- return [
6999
- ...startItems,
7000
- ...defaultItems,
7001
- ...endItems
7002
- ];
7003
- }
7077
+ const items = actions.filter((item) => !item.hidden);
7004
7078
  const handlerMap = {
7005
7079
  view: defaults.openView,
7006
7080
  edit: defaults.openEdit,
@@ -7252,15 +7326,18 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
7252
7326
  resource.handlers.openEdit,
7253
7327
  resource.handlers.openView
7254
7328
  ]);
7329
+ const { openComponent, dialog: rowActionDialog } = useRowActionDialog();
7255
7330
  const tableRowActions = react.useMemo(() => resolveActions(registryRowActions, rowActionDefaults, locale.rowActions, {
7256
7331
  crudId: id ?? "",
7257
- idKey: resourceIdKey
7332
+ idKey: resourceIdKey,
7333
+ openComponent
7258
7334
  }), [
7259
7335
  id,
7260
7336
  locale.rowActions,
7261
7337
  registryRowActions,
7262
7338
  resourceIdKey,
7263
- rowActionDefaults
7339
+ rowActionDefaults,
7340
+ openComponent
7264
7341
  ]);
7265
7342
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7266
7343
  className: "space-y-4",
@@ -7356,6 +7433,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
7356
7433
  pageCount: resource.tableData.pageCount,
7357
7434
  ...resource.tableData.total !== void 0 ? { total: resource.tableData.total } : {},
7358
7435
  overrides: tableOverrides,
7436
+ classNames: tableConfig?.classNames,
7359
7437
  exclude: hiddenColumns,
7360
7438
  filterMode: tableConfig?.filterModes,
7361
7439
  search: searchConfig,
@@ -7371,6 +7449,7 @@ function AutoCrudTable({ id, title, description, schema, resource, fields, table
7371
7449
  onSelectedRowsChange: handleSelectedRowsChange,
7372
7450
  getSelectedRows: getSelectedRowsRef
7373
7451
  }),
7452
+ rowActionDialog,
7374
7453
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CrudFormModal, {
7375
7454
  open: resource.modal.createOpen || resource.modal.editOpen,
7376
7455
  onOpenChange: (open) => !open && resource.handlers.closeModals(),