@atscript/vue-table 0.1.132 → 0.1.133

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/as-action-form-dialog.cjs +42 -30
  2. package/dist/as-action-form-dialog.mjs +42 -30
  3. package/dist/{as-action-menu-content-4UfcabUe.mjs → as-action-menu-content-4D7CJNgr.mjs} +1 -1
  4. package/dist/{as-action-menu-content-C5qx9MPE.cjs → as-action-menu-content-DiS37BYK.cjs} +1 -1
  5. package/dist/as-column-menu.d.cts +1 -1
  6. package/dist/as-column-menu.d.mts +1 -1
  7. package/dist/{as-column-menu.vue-DL5N9mKR.d.mts → as-column-menu.vue-CZ8XqHl0.d.cts} +2 -2
  8. package/dist/{as-column-menu.vue-u_DNy3f-.d.cts → as-column-menu.vue-Cuelpv3p.d.mts} +2 -2
  9. package/dist/{as-config-dialog-BehfqIGd.mjs → as-config-dialog-BKsm8OHR.mjs} +30 -22
  10. package/dist/{as-config-dialog-BOYWPYYH.cjs → as-config-dialog-Bt8oP8qg.cjs} +29 -21
  11. package/dist/as-config-dialog.cjs +1 -1
  12. package/dist/as-config-dialog.mjs +1 -1
  13. package/dist/{as-confirm-dialog-bpN4A-KN.mjs → as-confirm-dialog-BV01t7dn.mjs} +12 -9
  14. package/dist/{as-confirm-dialog-UwhDHysk.cjs → as-confirm-dialog-Cw7KErhz.cjs} +12 -9
  15. package/dist/as-confirm-dialog.cjs +1 -1
  16. package/dist/as-confirm-dialog.mjs +1 -1
  17. package/dist/{as-filter-dialog-Dh2Ylthb.cjs → as-filter-dialog-Bxii-mYH.cjs} +31 -23
  18. package/dist/{as-filter-dialog-D1qzq-8b.mjs → as-filter-dialog-Ckrl79kU.mjs} +32 -24
  19. package/dist/as-filter-dialog.cjs +1 -1
  20. package/dist/as-filter-dialog.mjs +1 -1
  21. package/dist/{as-filter-field-DirBmnbb.mjs → as-filter-field-C-IFnj8K.mjs} +4 -4
  22. package/dist/{as-filter-field-DRsDJdpx.cjs → as-filter-field-xBr6TtKo.cjs} +4 -4
  23. package/dist/as-filter-field.cjs +1 -1
  24. package/dist/as-filter-field.mjs +1 -1
  25. package/dist/as-filters-DJEQj7_p.mjs +125 -0
  26. package/dist/as-filters-DuCk8nkk.cjs +130 -0
  27. package/dist/as-filters.cjs +1 -1
  28. package/dist/as-filters.d.cts +1 -1
  29. package/dist/as-filters.d.mts +1 -1
  30. package/dist/as-filters.mjs +1 -1
  31. package/dist/as-filters.vue-BG_ysCkC.d.mts +65 -0
  32. package/dist/as-filters.vue-DcxDnWAU.d.cts +65 -0
  33. package/dist/{as-preset-dialog-CDqCAR7N.mjs → as-preset-dialog-CCIacZ2C.mjs} +70 -20
  34. package/dist/{as-preset-dialog-DpM06jqR.cjs → as-preset-dialog-jZeyXJeJ.cjs} +74 -24
  35. package/dist/as-preset-dialog.cjs +1 -1
  36. package/dist/as-preset-dialog.mjs +1 -1
  37. package/dist/{as-preset-picker-jUS_YDX8.cjs → as-preset-picker-4xXU1KQz.cjs} +45 -21
  38. package/dist/{as-preset-picker-CISaxEZ0.mjs → as-preset-picker-DGSqQl9A.mjs} +39 -15
  39. package/dist/as-preset-picker.cjs +1 -1
  40. package/dist/as-preset-picker.mjs +1 -1
  41. package/dist/{as-row-actions-Bm6Bzyno.cjs → as-row-actions-B_OHWIAt.cjs} +2 -2
  42. package/dist/{as-row-actions-xqJeAdQl.mjs → as-row-actions-pukI1JT7.mjs} +2 -2
  43. package/dist/as-row-actions.cjs +1 -1
  44. package/dist/as-row-actions.mjs +1 -1
  45. package/dist/{as-table-BWUPzjRn.cjs → as-table-BejpMVid.cjs} +22 -4
  46. package/dist/{as-table-CDSG2yED.mjs → as-table-D5_bQ0p5.mjs} +22 -4
  47. package/dist/{as-table-actions-DMxeaczm.mjs → as-table-actions-DKYK_mTO.mjs} +57 -11
  48. package/dist/{as-table-actions-gV4lqqxc.cjs → as-table-actions-qb0gQz2D.cjs} +56 -10
  49. package/dist/as-table-actions.cjs +1 -1
  50. package/dist/as-table-actions.d.cts +1 -1
  51. package/dist/as-table-actions.d.mts +1 -1
  52. package/dist/as-table-actions.mjs +1 -1
  53. package/dist/{as-table-actions.vue-B-cgiCXP.d.cts → as-table-actions.vue-CckRRsL6.d.cts} +2 -2
  54. package/dist/{as-table-actions.vue-ClMa0OD1.d.mts → as-table-actions.vue-DsqauvXR.d.mts} +2 -2
  55. package/dist/{as-table-base-BaTE3VSN.mjs → as-table-base-B0arhJI8.mjs} +141 -46
  56. package/dist/{as-table-base-RG2TEIgV.cjs → as-table-base-Dfw012G5.cjs} +141 -46
  57. package/dist/{as-table-header-cell-CIqlO6Lw.cjs → as-table-header-cell-Bb4ddLmQ.cjs} +1 -1
  58. package/dist/{as-table-header-cell-Bdhl5Lox.mjs → as-table-header-cell-q-c_QklI.mjs} +1 -1
  59. package/dist/as-table-header-cell.cjs +1 -1
  60. package/dist/as-table-header-cell.d.cts +1 -1
  61. package/dist/as-table-header-cell.d.mts +1 -1
  62. package/dist/as-table-header-cell.mjs +1 -1
  63. package/dist/{as-table-header-cell.vue-BCszzxtU.d.mts → as-table-header-cell.vue-BjVOEFqz.d.mts} +1 -1
  64. package/dist/{as-table-header-cell.vue-BzTzfGRo.d.cts → as-table-header-cell.vue-qS1Xfc-U.d.cts} +1 -1
  65. package/dist/{as-table-root-BLReUbRH.mjs → as-table-root-Bpsrp0Vz.mjs} +5 -5
  66. package/dist/{as-table-root-DLJ_3Jf4.cjs → as-table-root-CUDO9ybm.cjs} +5 -5
  67. package/dist/as-table-root.cjs +1 -1
  68. package/dist/as-table-root.d.cts +1 -1
  69. package/dist/as-table-root.d.mts +1 -1
  70. package/dist/as-table-root.mjs +1 -1
  71. package/dist/{as-table-root.vue-QMT93qPk.d.mts → as-table-root.vue-BPU92_Ns.d.mts} +55 -12
  72. package/dist/{as-table-root.vue-D0T3n-Vm.d.cts → as-table-root.vue-szvjZsCn.d.cts} +55 -12
  73. package/dist/{as-table-status-DGTZlpyq.mjs → as-table-status-B9jlzPPV.mjs} +53 -37
  74. package/dist/{as-table-status-Du4WLF4k.cjs → as-table-status-BgDexT2x.cjs} +53 -37
  75. package/dist/as-table.cjs +1 -1
  76. package/dist/as-table.d.cts +1 -1
  77. package/dist/as-table.d.mts +1 -1
  78. package/dist/as-table.mjs +1 -1
  79. package/dist/{as-table.vue-Ds7MEp37.d.cts → as-table.vue-4WhMA8AM.d.mts} +27 -3
  80. package/dist/{as-table.vue-Ce5606ZO.d.mts → as-table.vue-_urybtQj.d.cts} +27 -3
  81. package/dist/{as-window-table-jD_y9yet.cjs → as-window-table-CXq6UuUx.cjs} +98 -19
  82. package/dist/{as-window-table-DWujiUQy.mjs → as-window-table-S1XWpDHQ.mjs} +98 -19
  83. package/dist/as-window-table.cjs +1 -1
  84. package/dist/as-window-table.d.cts +1 -1
  85. package/dist/as-window-table.d.mts +1 -1
  86. package/dist/as-window-table.mjs +1 -1
  87. package/dist/{as-window-table.vue-DfZF1Mux.d.mts → as-window-table.vue-CWsJvOkL.d.mts} +25 -2
  88. package/dist/{as-window-table.vue-Bhf9BK8E.d.cts → as-window-table.vue-h1bdyMv7.d.cts} +25 -2
  89. package/dist/error-message-CglODWl4.cjs +18 -0
  90. package/dist/error-message-hPSAu8Ug.mjs +13 -0
  91. package/dist/index.cjs +61 -29
  92. package/dist/index.d.cts +9 -9
  93. package/dist/index.d.mts +9 -9
  94. package/dist/index.mjs +62 -30
  95. package/dist/{types-CTMxE_zA.d.cts → types-BZ0HssRY.d.cts} +126 -4
  96. package/dist/{types-ByU4O0Yf.d.mts → types-CXz-4dPz.d.mts} +126 -4
  97. package/dist/{use-table-CyFcVtUN.mjs → use-table-Bk-jSxOM.mjs} +26 -11
  98. package/dist/{use-table-nvBq1dZ4.cjs → use-table-CdFFqaEx.cjs} +24 -9
  99. package/dist/{use-table-component-DO_kvKSf.cjs → use-table-component-DlLganVc.cjs} +1 -1
  100. package/dist/{use-table-component-K6xj1obF.mjs → use-table-component-KuzZxAP8.mjs} +1 -1
  101. package/dist/{use-table-nav-bridge-DeGeaQX-.mjs → use-table-nav-bridge-B9SSEajW.mjs} +1 -1
  102. package/dist/{use-table-nav-bridge-uOQUDooh.cjs → use-table-nav-bridge-CVUmTjDr.cjs} +1 -1
  103. package/dist/{use-table-state-Oi2ds4_a.cjs → use-table-state-D6dHOFrA.cjs} +329 -53
  104. package/dist/{use-table-state-BxX3SpeW.mjs → use-table-state-DLJbW753.mjs} +295 -55
  105. package/package.json +9 -9
  106. package/dist/as-filters-DCZTHjf5.cjs +0 -51
  107. package/dist/as-filters-beIud9sF.mjs +0 -46
  108. package/dist/as-filters.vue-DmECMd1v.d.mts +0 -10
  109. package/dist/as-filters.vue-fv-tRL2H.d.cts +0 -10
  110. package/dist/preset-aspect-display-IICxAlVo.mjs +0 -43
  111. package/dist/preset-aspect-display-TWwf6j1B.cjs +0 -72
@@ -478,7 +478,18 @@ function buildRemoveAction(opts) {
478
478
  }
479
479
  //#endregion
480
480
  //#region src/composables/state/create-selection.ts
481
- function createSelectionApi(opts, getActiveRow) {
481
+ /** Shared verdicts — frozen, so the common case allocates nothing per row. */
482
+ const SELECTABLE = Object.freeze({ ok: true });
483
+ const NOT_SELECTABLE = Object.freeze({ ok: false });
484
+ /** Normalise a {@link RowSelectableHook} return value. `""` carries no reason. */
485
+ function verdictOf(value) {
486
+ if (value === void 0 || value === true) return SELECTABLE;
487
+ return value ? {
488
+ ok: false,
489
+ reason: value
490
+ } : NOT_SELECTABLE;
491
+ }
492
+ function createSelectionApi(opts, getActiveRow, activeIndex) {
482
493
  const selectedRows = opts?.selectedRows ?? (0, vue.shallowRef)([]);
483
494
  const selectedCount = (0, vue.computed)(() => selectedRows.value.length);
484
495
  const rowValueFn = opts?.rowValueFn ?? ((row) => row);
@@ -486,10 +497,49 @@ function createSelectionApi(opts, getActiveRow) {
486
497
  function isPkSelected(pk) {
487
498
  return selectedSet.value.has(pk);
488
499
  }
500
+ const rowSelectable = (0, vue.ref)();
501
+ function isRowSelectable(row, index) {
502
+ const hook = rowSelectable.value;
503
+ if (!hook) return SELECTABLE;
504
+ return verdictOf(hook(row, {
505
+ index,
506
+ get selected() {
507
+ return isPkSelected(rowValueFn(row));
508
+ }
509
+ }));
510
+ }
511
+ function selectableRows(rows) {
512
+ if (!rowSelectable.value) return rows;
513
+ return rows.filter((row, index) => isRowSelectable(row, index).ok);
514
+ }
515
+ function selectableCount(rows) {
516
+ if (!rowSelectable.value) return rows.length;
517
+ let n = 0;
518
+ for (let i = 0; i < rows.length; i++) if (isRowSelectable(rows[i], i).ok) n++;
519
+ return n;
520
+ }
521
+ function selectAll(rows, indexOf) {
522
+ if (!rowSelectable.value) {
523
+ selectedRows.value = (0, _atscript_ui_table.rowsToPks)(rows, rowValueFn);
524
+ return;
525
+ }
526
+ const out = [];
527
+ const seen = /* @__PURE__ */ new Set();
528
+ for (let i = 0; i < rows.length; i++) {
529
+ const row = rows[i];
530
+ const pk = rowValueFn(row);
531
+ if (seen.has(pk)) continue;
532
+ if (!isRowSelectable(row, indexOf ? indexOf(i) : i).ok && !isPkSelected(pk)) continue;
533
+ seen.add(pk);
534
+ out.push(pk);
535
+ }
536
+ selectedRows.value = out;
537
+ }
489
538
  function toggleActiveSelection(mode) {
490
539
  if (mode === "none") return;
491
540
  const row = getActiveRow();
492
541
  if (row === void 0) return;
542
+ if (!isRowSelectable(row, activeIndex.value).ok) return;
493
543
  selectedRows.value = (0, _atscript_ui_table.togglePk)(selectedRows.value, rowValueFn(row), mode);
494
544
  }
495
545
  return {
@@ -498,6 +548,11 @@ function createSelectionApi(opts, getActiveRow) {
498
548
  selectedSet,
499
549
  rowValueFn,
500
550
  isPkSelected,
551
+ rowSelectable,
552
+ isRowSelectable,
553
+ selectableRows,
554
+ selectableCount,
555
+ selectAll,
501
556
  toggleActiveSelection
502
557
  };
503
558
  }
@@ -551,6 +606,38 @@ function createMainActionRegistry(opts) {
551
606
  }
552
607
  //#endregion
553
608
  //#region src/composables/state/create-nav-controller.ts
609
+ /**
610
+ * Elements that own Enter / Space (and a pointer drag) themselves.
611
+ * `[contenteditable]` is matched separately because `contenteditable="false"`
612
+ * must NOT count.
613
+ */
614
+ const INTERACTIVE_SELECTOR = "button, a[href], input, select, textarea, summary, [role=button], [role=link], [role=checkbox], [role=menuitem], [role=switch], [role=tab], [role=option]";
615
+ /**
616
+ * True when the key event started on an interactive element inside a cell,
617
+ * so table nav must not consume Enter / Space. The walk runs from
618
+ * `event.target` up to `event.currentTarget` — the element the handler is
619
+ * bound on — and stops at the cell / row boundary, so a wrapper outside the
620
+ * table can never make a whole table inert. A handler bound ON the
621
+ * interactive element itself (the search-input bridge) is therefore never
622
+ * guarded: the walk has nothing to cross. An interactive element opts BACK
623
+ * IN to table nav — e.g. a cell whose button should not swallow Enter —
624
+ * with `data-as-nav-keys`.
625
+ */
626
+ function isInteractiveKeyTarget(event) {
627
+ let el = event.target;
628
+ const stop = event.currentTarget;
629
+ while (el && el !== stop && typeof el.matches === "function") {
630
+ const tag = el.tagName;
631
+ if (tag === "TD" || tag === "TH" || tag === "TR" || tag === "TBODY" || tag === "TABLE") return false;
632
+ if (el.matches("button, a[href], input, select, textarea, summary, [role=button], [role=link], [role=checkbox], [role=menuitem], [role=switch], [role=tab], [role=option]") || isEditable(el)) return !el.hasAttribute("data-as-nav-keys");
633
+ el = el.parentElement;
634
+ }
635
+ return false;
636
+ }
637
+ function isEditable(el) {
638
+ const attr = el.getAttribute("contenteditable");
639
+ return attr !== null && attr !== "false";
640
+ }
554
641
  function createNavController(inputs) {
555
642
  const { activeIndex, navMode, totalCount, results, viewportRowCount, topIndex, hasMainActionAvailable, requestMainAction, toggleActiveSelection } = inputs;
556
643
  const navViewportRowCount = (0, vue.ref)(0);
@@ -600,6 +687,7 @@ function createNavController(inputs) {
600
687
  const enterAction = opts?.enterAction ?? "main-action";
601
688
  const mode = opts?.mode ?? "none";
602
689
  const key = event.key;
690
+ const guarded = (key === "Enter" || key === " ") && isInteractiveKeyTarget(event);
603
691
  const meta = event.metaKey;
604
692
  const ctrl = event.ctrlKey;
605
693
  const alt = event.altKey;
@@ -650,11 +738,13 @@ function createNavController(inputs) {
650
738
  return;
651
739
  case " ":
652
740
  if (mode === "none") return;
741
+ if (guarded) return;
653
742
  event.preventDefault();
654
743
  toggleActiveSelection(mode);
655
744
  return;
656
745
  case "Enter":
657
746
  if (enterAction === "passthrough") return;
747
+ if (guarded) return;
658
748
  event.preventDefault();
659
749
  if (enterAction === "toggle-select") {
660
750
  toggleActiveSelection(mode);
@@ -679,6 +769,67 @@ function createNavController(inputs) {
679
769
  handleNavKey
680
770
  };
681
771
  }
772
+ /**
773
+ * `@keydown` handler for a row's SELECTION CONTROL (the leading checkbox),
774
+ * shared by `<AsTableBase>` and `<AsWindowTableBase>`. The control carries
775
+ * `role="checkbox"`, so the tbody-level nav handler deliberately leaves
776
+ * Space to it (see {@link isInteractiveKeyTarget}) — this is where it lands.
777
+ *
778
+ * Keys other than Space, and `select="none"`, fall through untouched; only
779
+ * once the press is ours do we consume it, so the Reka-wrapped rendering
780
+ * modes (which never bind this handler) keep Space for their own item.
781
+ * Selectability is NOT re-checked here: `toggleActiveSelection` gates on
782
+ * `rowSelectable` itself, which is the single place that rule lives.
783
+ */
784
+ function onSelectControlKeydown(event, index, mode, state) {
785
+ if (event.key !== " ") return;
786
+ if (mode === "none") return;
787
+ event.preventDefault();
788
+ event.stopPropagation();
789
+ state.setActive(index);
790
+ state.toggleActiveSelection(mode);
791
+ }
792
+ //#endregion
793
+ //#region src/composables/preset-aspect-display.ts
794
+ const ASPECT_LABELS = {
795
+ columns: "Displayed Columns",
796
+ filters: "Displayed Filters",
797
+ filterOps: "Filter conditions",
798
+ sorters: "Sorters",
799
+ itemsPerPage: "Page size"
800
+ };
801
+ const ASPECT_ICONS = {
802
+ columns: "i-as-columns",
803
+ filters: "i-as-filter",
804
+ filterOps: "i-as-filter-ops",
805
+ sorters: "i-as-sorters",
806
+ itemsPerPage: "i-as-pin"
807
+ };
808
+ /**
809
+ * Resolve the aspects a stored preset claims. Prefers the server-stamped
810
+ * `aspects` column (cheap), falls back to deriving from `data.content` for
811
+ * older rows or first paint after save before reload settles.
812
+ */
813
+ function aspectsOf(row, availableAspects) {
814
+ if (Array.isArray(row.aspects) && row.aspects.length > 0) return row.aspects.filter((a) => availableAspects.includes(a));
815
+ const wire = row.data?.content;
816
+ if (!wire) return [];
817
+ return (0, _atscript_ui_table.derivePresetAspects)(wire).filter((a) => availableAspects.includes(a));
818
+ }
819
+ function readPresetLabel(row) {
820
+ return row.label ?? row.data?.label ?? row.id;
821
+ }
822
+ /**
823
+ * Display name for the row's owner. `userLabel` (server-stamped via the
824
+ * host's `getUserLabel` hook) is preferred so the UI shows "Alice" rather
825
+ * than `usr_abc123`. `fallback` is returned when no name is available —
826
+ * picker uses `""`, dialog uses `"—"`.
827
+ */
828
+ function ownerNameOf(row, fallback = "") {
829
+ if (typeof row.userLabel === "string" && row.userLabel.length > 0) return row.userLabel;
830
+ if (typeof row.user === "string" && row.user.length > 0) return row.user;
831
+ return fallback;
832
+ }
682
833
  //#endregion
683
834
  //#region src/composables/state/create-preset-state.ts
684
835
  const DEFAULT_AVAILABLE_ASPECTS = [
@@ -705,6 +856,26 @@ function defaultColumnPaths(o) {
705
856
  function createPresetState(opts) {
706
857
  const availableAspects = opts.availableAspects ?? DEFAULT_AVAILABLE_ASPECTS;
707
858
  const availableSet = new Set(availableAspects);
859
+ const systemAspects = opts.systemAspects ? availableAspects.filter((a) => opts.systemAspects.includes(a)) : availableAspects;
860
+ const lastError = (0, vue.ref)(null);
861
+ let trackDepth = 0;
862
+ /**
863
+ * Every public mutator runs through here: it is the one place a preset
864
+ * write failure is recorded. Clears `lastError` on the outermost entry,
865
+ * records the failure and RETHROWS so the caller can react too.
866
+ */
867
+ async function track(fn) {
868
+ if (trackDepth === 0) lastError.value = null;
869
+ trackDepth++;
870
+ try {
871
+ return await fn();
872
+ } catch (err) {
873
+ lastError.value = err instanceof Error ? err : new Error(String(err));
874
+ throw err;
875
+ } finally {
876
+ trackDepth--;
877
+ }
878
+ }
708
879
  const dialogOpen = (0, vue.ref)(false);
709
880
  const gate = (0, vue.ref)(false);
710
881
  const ready = (0, vue.computed)(() => opts.presetsHandle ? gate.value : true);
@@ -795,6 +966,20 @@ function createPresetState(opts) {
795
966
  if (!mask) return true;
796
967
  return mask[aspect] === true;
797
968
  }
969
+ /**
970
+ * Aspects the preset `id` OWNS, i.e. the ones applying it may write:
971
+ * a system preset owns `systemAspects`, a stored preset owns what its
972
+ * snapshot claims, and "no preset" (a raw snapshot, or an id with no row)
973
+ * owns everything available. The one answer every aspect-scoped surface
974
+ * asks for — apply, system-snapshot expansion, the picker badges and
975
+ * Save-as mask, the manage dialog rows.
976
+ */
977
+ function ownedAspects(id) {
978
+ if (!id) return availableAspects;
979
+ if ((0, _atscript_ui_table.isSystemPresetId)(id)) return systemAspects;
980
+ const row = presetsById.value.get(id);
981
+ return row ? aspectsOf(row, availableAspects) : availableAspects;
982
+ }
798
983
  function captureSnapshot(mask) {
799
984
  const out = {};
800
985
  for (const aspect of availableAspects) {
@@ -834,7 +1019,7 @@ function createPresetState(opts) {
834
1019
  function apply(idOrSnapshot) {
835
1020
  const { snapshot, nextActiveId } = resolveSnapshot(idOrSnapshot);
836
1021
  const isSystem = typeof idOrSnapshot === "string" && nextActiveId !== null && (0, _atscript_ui_table.isSystemPresetId)(nextActiveId);
837
- for (const aspect of availableAspects) {
1022
+ for (const aspect of ownedAspects(nextActiveId)) {
838
1023
  const value = snapshot[aspect];
839
1024
  ASPECT_HANDLERS[aspect].apply(opts, value, isSystem);
840
1025
  }
@@ -860,9 +1045,12 @@ function createPresetState(opts) {
860
1045
  * "claims all aspects in `availableAspects`" per spec §3.7. Stored presets
861
1046
  * keep dict-form opt-in (untouched).
862
1047
  */
863
- function expandSystemSnapshot(snapshot) {
864
- const out = { ...snapshot };
865
- for (const aspect of availableAspects) {
1048
+ function expandSystemSnapshot(snapshot, id) {
1049
+ const out = {};
1050
+ const owned = ownedAspects(id);
1051
+ const ownedSet = new Set(owned);
1052
+ for (const [key, value] of Object.entries(snapshot)) if (ownedSet.has(key)) out[key] = value;
1053
+ for (const aspect of owned) {
866
1054
  const handler = ASPECT_HANDLERS[aspect];
867
1055
  if (!handler.expandDefault) continue;
868
1056
  if (out[aspect] !== void 0) continue;
@@ -873,7 +1061,7 @@ function createPresetState(opts) {
873
1061
  const activeSnapshot = (0, vue.computed)(() => {
874
1062
  const id = activeId.value;
875
1063
  if (!id) return {};
876
- if ((0, _atscript_ui_table.isSystemPresetId)(id)) return expandSystemSnapshot(systemPresetsById.value.get(id)?.content ?? {});
1064
+ if ((0, _atscript_ui_table.isSystemPresetId)(id)) return expandSystemSnapshot(systemPresetsById.value.get(id)?.content ?? {}, id);
877
1065
  const row = presetsById.value.get(id);
878
1066
  if (!row) return {};
879
1067
  const wire = row.data?.content;
@@ -884,48 +1072,64 @@ function createPresetState(opts) {
884
1072
  if (!opts.presetsHandle) throw new Error("[vue-table] presets feature not configured (preset.url missing)");
885
1073
  return opts.presetsHandle;
886
1074
  }
887
- async function saveActive() {
888
- const handle = requirePresets();
889
- const id = activeId.value;
890
- if (!id) throw new Error("[vue-table] saveActive: no active preset");
891
- if ((0, _atscript_ui_table.isSystemPresetId)(id)) throw new Error("[vue-table] saveActive: system presets cannot be overwritten");
892
- const existing = activeSnapshot.value;
893
- const mask = {};
894
- for (const aspect of availableAspects) if (existing[aspect] !== void 0) mask[aspect] = true;
895
- await handle.savePreset(captureSnapshot(mask));
896
- clearLocalDraft();
897
- }
898
- async function saveAs(label, saveOpts = {}) {
899
- const id = await requirePresets().savePresetAs(label, captureSnapshot(saveOpts.aspects), { public: saveOpts.public });
900
- clearLocalDraft();
901
- return id;
902
- }
903
- async function rename(id, label) {
904
- await requirePresets().renamePreset(id, label);
905
- }
906
- async function remove(id) {
907
- const handle = requirePresets();
908
- const wasActive = activeId.value === id;
909
- await handle.deletePreset(id);
910
- if (wasActive) {
911
- apply(_atscript_ui_table.STANDARD_PRESET_ID);
1075
+ function saveActive() {
1076
+ return track(async () => {
1077
+ const handle = requirePresets();
1078
+ const id = activeId.value;
1079
+ if (!id) throw new Error("[vue-table] saveActive: no active preset");
1080
+ if ((0, _atscript_ui_table.isSystemPresetId)(id)) throw new Error("[vue-table] saveActive: system presets cannot be overwritten");
1081
+ const existing = activeSnapshot.value;
1082
+ const mask = {};
1083
+ for (const aspect of availableAspects) if (existing[aspect] !== void 0) mask[aspect] = true;
1084
+ await handle.savePreset(captureSnapshot(mask));
912
1085
  clearLocalDraft();
913
- }
1086
+ });
1087
+ }
1088
+ function saveAs(label, saveOpts = {}) {
1089
+ return track(async () => {
1090
+ const id = await requirePresets().savePresetAs(label, captureSnapshot(saveOpts.aspects), { public: saveOpts.public });
1091
+ clearLocalDraft();
1092
+ return id;
1093
+ });
1094
+ }
1095
+ function rename(id, label) {
1096
+ return track(async () => {
1097
+ await requirePresets().renamePreset(id, label);
1098
+ });
1099
+ }
1100
+ function remove(id) {
1101
+ return track(async () => {
1102
+ const handle = requirePresets();
1103
+ const wasActive = activeId.value === id;
1104
+ await handle.deletePreset(id);
1105
+ if (wasActive) {
1106
+ apply(_atscript_ui_table.STANDARD_PRESET_ID);
1107
+ clearLocalDraft();
1108
+ }
1109
+ });
914
1110
  }
915
- async function togglePublic(id) {
916
- await requirePresets().togglePublic(id);
1111
+ function togglePublic(id) {
1112
+ return track(async () => {
1113
+ await requirePresets().togglePublic(id);
1114
+ });
917
1115
  }
918
- async function setDefault(id) {
919
- await requirePresets().setDefault(id);
1116
+ function setDefault(id) {
1117
+ return track(async () => {
1118
+ await requirePresets().setDefault(id);
1119
+ });
920
1120
  }
921
- async function toggleFav(id) {
922
- await requirePresets().toggleFav(id);
1121
+ function toggleFav(id) {
1122
+ return track(async () => {
1123
+ await requirePresets().toggleFav(id);
1124
+ });
923
1125
  }
924
- async function setFavorites(ids) {
925
- await requirePresets().setFavorites(ids);
1126
+ function setFavorites(ids) {
1127
+ return track(async () => {
1128
+ await requirePresets().setFavorites(ids);
1129
+ });
926
1130
  }
927
1131
  function batch(fn) {
928
- return opts.presetsHandle ? opts.presetsHandle.batch(fn) : fn();
1132
+ return track(() => opts.presetsHandle ? opts.presetsHandle.batch(fn) : fn());
929
1133
  }
930
1134
  function resolveDefaultId() {
931
1135
  const pinned = (userConf.value?.data)?.defaultPresetId;
@@ -941,7 +1145,7 @@ function createPresetState(opts) {
941
1145
  stop();
942
1146
  const id = resolveDefaultId();
943
1147
  const { snapshot, nextActiveId } = resolveSnapshot(id);
944
- const base = (0, _atscript_ui_table.isSystemPresetId)(id) ? expandSystemSnapshot(snapshot) : snapshot;
1148
+ const base = (0, _atscript_ui_table.isSystemPresetId)(id) ? expandSystemSnapshot(snapshot, id) : snapshot;
945
1149
  const draftEnabled = !!(opts.draftHandle && opts.persistDrafts);
946
1150
  apply(draftEnabled ? opts.draftHandle.hydrate(base) : base);
947
1151
  activeId.value = nextActiveId;
@@ -960,6 +1164,8 @@ function createPresetState(opts) {
960
1164
  systemPresets,
961
1165
  systemPresetsById,
962
1166
  availableAspects,
1167
+ systemAspects,
1168
+ ownedAspects,
963
1169
  available,
964
1170
  activeId,
965
1171
  activeSnapshot,
@@ -982,7 +1188,8 @@ function createPresetState(opts) {
982
1188
  setDefault,
983
1189
  toggleFav,
984
1190
  setFavorites,
985
- batch
1191
+ batch,
1192
+ lastError
986
1193
  },
987
1194
  internals: {
988
1195
  gate,
@@ -1252,17 +1459,20 @@ function cellAsString(v) {
1252
1459
  */
1253
1460
  function createRequestSlot(cancelValue) {
1254
1461
  const r = (0, vue.shallowRef)(null);
1462
+ const display = (0, vue.shallowRef)(null);
1255
1463
  function request(body) {
1256
1464
  if (r.value) {
1257
1465
  r.value.resolve(cancelValue);
1258
1466
  r.value = null;
1259
1467
  }
1260
- return new Promise((resolve) => {
1468
+ const promise = new Promise((resolve) => {
1261
1469
  r.value = {
1262
1470
  ...body,
1263
1471
  resolve
1264
1472
  };
1265
1473
  });
1474
+ display.value = r.value;
1475
+ return promise;
1266
1476
  }
1267
1477
  function accept(value) {
1268
1478
  const req = r.value;
@@ -1276,11 +1486,16 @@ function createRequestSlot(cancelValue) {
1276
1486
  r.value = null;
1277
1487
  req.resolve(cancelValue);
1278
1488
  }
1489
+ function release() {
1490
+ if (r.value === null) display.value = null;
1491
+ }
1279
1492
  return {
1280
1493
  ref: r,
1494
+ display,
1281
1495
  request,
1282
1496
  accept,
1283
- dismiss
1497
+ dismiss,
1498
+ release
1284
1499
  };
1285
1500
  }
1286
1501
  function createTableState(opts) {
@@ -1360,6 +1575,7 @@ function createTableState(opts) {
1360
1575
  presetsHandle: opts.preset?.presetsHandle,
1361
1576
  draftHandle: opts.preset?.draftHandle,
1362
1577
  availableAspects: opts.preset?.availableAspects,
1578
+ systemAspects: opts.preset?.systemAspects,
1363
1579
  persistDrafts: opts.preset?.persistDrafts,
1364
1580
  fallbackSystemPresets: opts.preset?.fallbackSystemPresets
1365
1581
  });
@@ -1372,8 +1588,10 @@ function createTableState(opts) {
1372
1588
  message
1373
1589
  });
1374
1590
  }
1591
+ const confirmDisplay = promptSlot.display;
1375
1592
  const acceptPrompt = () => promptSlot.accept(true);
1376
1593
  const dismissPrompt = promptSlot.dismiss;
1594
+ const releaseConfirm = promptSlot.release;
1377
1595
  const formSlot = createRequestSlot(null);
1378
1596
  const actionFormRequest = formSlot.ref;
1379
1597
  function requestActionInput(action, ctx) {
@@ -1383,8 +1601,10 @@ function createTableState(opts) {
1383
1601
  preferredId: ctx.preferredId
1384
1602
  });
1385
1603
  }
1604
+ const actionFormDisplay = formSlot.display;
1386
1605
  const acceptActionForm = formSlot.accept;
1387
1606
  const dismissActionForm = formSlot.dismiss;
1607
+ const releaseActionForm = formSlot.release;
1388
1608
  const stateUid = `tbl-${++_tblUid}`;
1389
1609
  function rowId(absIndex) {
1390
1610
  return `${stateUid}-row-${absIndex}`;
@@ -1426,6 +1646,10 @@ function createTableState(opts) {
1426
1646
  /** -1 == nothing active. */
1427
1647
  const activeIndex = (0, vue.ref)(-1);
1428
1648
  const navMode = (0, vue.ref)("pagination");
1649
+ const isQueryBlocked = (0, vue.computed)(() => {
1650
+ const blocked = queryOpts?.blockQuery;
1651
+ return typeof blocked === "function" ? !!blocked() : !!blocked;
1652
+ });
1429
1653
  const { windowCache, windowLoading, errors, topIndex, viewportRowCount, dataAt, loadingAt, errorAt, loadRange, queryNext, clearSettlements, resetWindow, disposeDebounces } = createWindowFetcher({
1430
1654
  blockSize,
1431
1655
  dragReleaseDebounceMs,
@@ -1435,7 +1659,7 @@ function createTableState(opts) {
1435
1659
  resultsStart,
1436
1660
  queryingNext,
1437
1661
  getGeneration: () => generation,
1438
- isQueryBlocked: () => !!queryOpts?.blockQuery,
1662
+ isQueryBlocked: () => isQueryBlocked.value,
1439
1663
  buildCurrentQuery,
1440
1664
  dispatchPages,
1441
1665
  reportError
@@ -1445,7 +1669,7 @@ function createTableState(opts) {
1445
1669
  if (idx < 0) return void 0;
1446
1670
  return navMode.value === "window" ? dataAt(idx) : results.value[idx];
1447
1671
  }
1448
- const { selectedRows, selectedCount, rowValueFn, isPkSelected, toggleActiveSelection } = createSelectionApi(selectionOpts, getActiveRow);
1672
+ const { selectedRows, selectedCount, rowValueFn, isPkSelected, rowSelectable, isRowSelectable, selectableRows, selectableCount, selectAll, toggleActiveSelection } = createSelectionApi(selectionOpts, getActiveRow, activeIndex);
1449
1673
  const { actions } = createActions({
1450
1674
  tableDef,
1451
1675
  client,
@@ -1481,7 +1705,7 @@ function createTableState(opts) {
1481
1705
  toggleActiveSelection
1482
1706
  });
1483
1707
  async function runQuery(kind, silent = false) {
1484
- if (queryOpts?.blockQuery) return;
1708
+ if (isQueryBlocked.value) return;
1485
1709
  mustRefresh.value = false;
1486
1710
  if (!silent && kind !== "initial" && topIndex.value !== 0) topIndex.value = 0;
1487
1711
  const thisGen = ++generation;
@@ -1522,7 +1746,7 @@ function createTableState(opts) {
1522
1746
  let pendingSilent = true;
1523
1747
  let queryFlushScheduled = false;
1524
1748
  function scheduleQuery(kind = "query", opts) {
1525
- if (queryOpts?.blockQuery) return;
1749
+ if (isQueryBlocked.value) return;
1526
1750
  if (tableDef.value === null) return;
1527
1751
  pendingScheduledKind = pendingScheduledKind ?? kind;
1528
1752
  if (!(opts?.silent ?? false)) {
@@ -1552,7 +1776,7 @@ function createTableState(opts) {
1552
1776
  async function queryImmediate(opts) {
1553
1777
  pendingScheduledKind = null;
1554
1778
  pendingSilent = true;
1555
- if (queryOpts?.blockQuery) return;
1779
+ if (isQueryBlocked.value) return;
1556
1780
  if (tableDef.value === null) return;
1557
1781
  await runQuery("query", opts?.silent ?? false);
1558
1782
  }
@@ -1610,6 +1834,11 @@ function createTableState(opts) {
1610
1834
  rowValueFn,
1611
1835
  resolveHref: opts.actions?.resolveHref ?? ((url) => url),
1612
1836
  isPkSelected,
1837
+ rowSelectable,
1838
+ isRowSelectable,
1839
+ selectableRows,
1840
+ selectableCount,
1841
+ selectAll,
1613
1842
  rowDelete,
1614
1843
  includeActions,
1615
1844
  activeIndex,
@@ -1625,13 +1854,17 @@ function createTableState(opts) {
1625
1854
  registerMainActionListener,
1626
1855
  actions,
1627
1856
  confirmRequest,
1857
+ confirmDisplay,
1628
1858
  prompt: promptFn,
1629
1859
  acceptPrompt,
1630
1860
  dismissPrompt,
1861
+ releaseConfirm,
1631
1862
  actionFormRequest,
1863
+ actionFormDisplay,
1632
1864
  requestActionInput,
1633
1865
  acceptActionForm,
1634
1866
  dismissActionForm,
1867
+ releaseActionForm,
1635
1868
  query,
1636
1869
  queryImmediate,
1637
1870
  queryNext,
@@ -1777,7 +2010,7 @@ function createTableState(opts) {
1777
2010
  lastEmittedUrl = serializeStateForUrl();
1778
2011
  (0, vue.nextTick)(() => {
1779
2012
  hydratingFromUrl = false;
1780
- if (wasQueryDetected && !queryOpts?.blockQuery && tableDef.value !== null) scheduleQuery();
2013
+ if (wasQueryDetected && !isQueryBlocked.value && tableDef.value !== null) scheduleQuery();
1781
2014
  });
1782
2015
  }
1783
2016
  const debouncedFilterQuery = (0, _atscript_ui_table.debounce)(() => {
@@ -1838,9 +2071,11 @@ function createTableState(opts) {
1838
2071
  (0, vue.watch)([
1839
2072
  () => tableDef.value,
1840
2073
  () => queryOpts?.urlQueryReady?.value ?? true,
1841
- presetGateOpen
1842
- ], ([def, urlReady, presetReady]) => {
2074
+ presetGateOpen,
2075
+ () => isQueryBlocked.value
2076
+ ], ([def, urlReady, presetReady, blocked]) => {
1843
2077
  if (queryDetected) return;
2078
+ if (blocked) return;
1844
2079
  if (def === null || !urlReady || !presetReady) return;
1845
2080
  if (queryOpts?.queryOnMount === false) return;
1846
2081
  if (allColumns.value.length === 0) return;
@@ -1848,6 +2083,11 @@ function createTableState(opts) {
1848
2083
  queryDetected = true;
1849
2084
  scheduleQuery("initial");
1850
2085
  });
2086
+ (0, vue.watch)(() => isQueryBlocked.value, (blocked) => {
2087
+ if (blocked || !queryDetected) return;
2088
+ if (tableDef.value === null) return;
2089
+ scheduleQuery();
2090
+ });
1851
2091
  (0, vue.onScopeDispose)(() => {
1852
2092
  debouncedFilterQuery.cancel();
1853
2093
  disposeDebounces();
@@ -1994,12 +2234,30 @@ function useRegisterMainActionListener(state, listener, enabled) {
1994
2234
  });
1995
2235
  }
1996
2236
  //#endregion
2237
+ Object.defineProperty(exports, "ASPECT_ICONS", {
2238
+ enumerable: true,
2239
+ get: function() {
2240
+ return ASPECT_ICONS;
2241
+ }
2242
+ });
2243
+ Object.defineProperty(exports, "ASPECT_LABELS", {
2244
+ enumerable: true,
2245
+ get: function() {
2246
+ return ASPECT_LABELS;
2247
+ }
2248
+ });
1997
2249
  Object.defineProperty(exports, "DEFAULT_AVAILABLE_ASPECTS", {
1998
2250
  enumerable: true,
1999
2251
  get: function() {
2000
2252
  return DEFAULT_AVAILABLE_ASPECTS;
2001
2253
  }
2002
2254
  });
2255
+ Object.defineProperty(exports, "INTERACTIVE_SELECTOR", {
2256
+ enumerable: true,
2257
+ get: function() {
2258
+ return INTERACTIVE_SELECTOR;
2259
+ }
2260
+ });
2003
2261
  Object.defineProperty(exports, "ROW_ACTIONS_PATH", {
2004
2262
  enumerable: true,
2005
2263
  get: function() {
@@ -2090,12 +2348,30 @@ Object.defineProperty(exports, "isPlainLeftClick", {
2090
2348
  return isPlainLeftClick;
2091
2349
  }
2092
2350
  });
2351
+ Object.defineProperty(exports, "onSelectControlKeydown", {
2352
+ enumerable: true,
2353
+ get: function() {
2354
+ return onSelectControlKeydown;
2355
+ }
2356
+ });
2357
+ Object.defineProperty(exports, "ownerNameOf", {
2358
+ enumerable: true,
2359
+ get: function() {
2360
+ return ownerNameOf;
2361
+ }
2362
+ });
2093
2363
  Object.defineProperty(exports, "provideTableContext", {
2094
2364
  enumerable: true,
2095
2365
  get: function() {
2096
2366
  return provideTableContext;
2097
2367
  }
2098
2368
  });
2369
+ Object.defineProperty(exports, "readPresetLabel", {
2370
+ enumerable: true,
2371
+ get: function() {
2372
+ return readPresetLabel;
2373
+ }
2374
+ });
2099
2375
  Object.defineProperty(exports, "triggerAction", {
2100
2376
  enumerable: true,
2101
2377
  get: function() {