@atscript/vue-table 0.1.111 → 0.1.113

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 (99) hide show
  1. package/dist/as-action-form-dialog.cjs +1 -1
  2. package/dist/as-action-form-dialog.mjs +1 -1
  3. package/dist/{as-action-menu-content-B6rWBo5O.cjs → as-action-menu-content-C7n_dJx0.cjs} +63 -7
  4. package/dist/{as-action-menu-content-CXG6BhWe.mjs → as-action-menu-content-CWmWeQam.mjs} +63 -7
  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-DZawdGvY.d.cts → as-column-menu.vue-DL5N9mKR.d.mts} +2 -2
  8. package/dist/{as-column-menu.vue-csCNmAYR.d.mts → as-column-menu.vue-u_DNy3f-.d.cts} +2 -2
  9. package/dist/{as-config-dialog-DAqSy8zx.mjs → as-config-dialog-0e-az0nn.mjs} +2 -2
  10. package/dist/{as-config-dialog-DKYI4uQ0.cjs → as-config-dialog-B6MFmBRW.cjs} +2 -2
  11. package/dist/as-config-dialog.cjs +1 -1
  12. package/dist/as-config-dialog.mjs +1 -1
  13. package/dist/{as-confirm-dialog-BqvOf3yo.cjs → as-confirm-dialog-CYiLQUP-.cjs} +1 -1
  14. package/dist/{as-confirm-dialog-B1zuisFu.mjs → as-confirm-dialog-DlZzfASO.mjs} +1 -1
  15. package/dist/as-confirm-dialog.cjs +1 -1
  16. package/dist/as-confirm-dialog.mjs +1 -1
  17. package/dist/{as-filter-dialog-BIj0ABzy.mjs → as-filter-dialog-Bole60UC.mjs} +7 -7
  18. package/dist/{as-filter-dialog-PBy9IDBz.cjs → as-filter-dialog-OiRuTYfh.cjs} +7 -7
  19. package/dist/as-filter-dialog.cjs +1 -1
  20. package/dist/as-filter-dialog.mjs +1 -1
  21. package/dist/{as-filter-field-BHPZtUwd.cjs → as-filter-field-iJbKFVSw.cjs} +3 -3
  22. package/dist/{as-filter-field-9mG-alNU.mjs → as-filter-field-xzcm2aGE.mjs} +3 -3
  23. package/dist/as-filter-field.cjs +1 -1
  24. package/dist/as-filter-field.mjs +1 -1
  25. package/dist/{as-filters-BSQ3nugx.mjs → as-filters-CGRd9vX0.mjs} +3 -3
  26. package/dist/{as-filters-7oIkmDHI.cjs → as-filters-DfkxKGNU.cjs} +3 -3
  27. package/dist/as-filters.cjs +1 -1
  28. package/dist/as-filters.mjs +1 -1
  29. package/dist/{as-preset-dialog-CuWw5fuN.mjs → as-preset-dialog-BbnwfYzC.mjs} +1 -1
  30. package/dist/{as-preset-dialog-BXO1O1q0.cjs → as-preset-dialog-D77Dg9ll.cjs} +1 -1
  31. package/dist/as-preset-dialog.cjs +1 -1
  32. package/dist/as-preset-dialog.mjs +1 -1
  33. package/dist/{as-preset-picker-CyBbOnBS.mjs → as-preset-picker-Bwr3kM4o.mjs} +1 -1
  34. package/dist/{as-preset-picker-BBkjl0fs.cjs → as-preset-picker-Divz_1ZG.cjs} +1 -1
  35. package/dist/as-preset-picker.cjs +1 -1
  36. package/dist/as-preset-picker.mjs +1 -1
  37. package/dist/{as-row-actions-DIpn-EYD.mjs → as-row-actions-CBVF6B2-.mjs} +55 -28
  38. package/dist/{as-row-actions-BoOAXAeW.cjs → as-row-actions-DC6-kpsJ.cjs} +54 -27
  39. package/dist/as-row-actions.cjs +1 -1
  40. package/dist/as-row-actions.mjs +1 -1
  41. package/dist/{as-table-QkKHAIh6.mjs → as-table-DQwYi63u.mjs} +2 -2
  42. package/dist/{as-table-C3Li7WTI.cjs → as-table-DaT2K-7n.cjs} +2 -2
  43. package/dist/{as-table-actions-Cd7KoTEK.cjs → as-table-actions-CEhZXH97.cjs} +48 -19
  44. package/dist/{as-table-actions-DQ3xaFXJ.mjs → as-table-actions-ChR9MGQt.mjs} +49 -20
  45. package/dist/as-table-actions.cjs +1 -1
  46. package/dist/as-table-actions.d.cts +1 -1
  47. package/dist/as-table-actions.d.mts +1 -1
  48. package/dist/as-table-actions.mjs +1 -1
  49. package/dist/{as-table-actions.vue-DW-zOVP0.d.cts → as-table-actions.vue-DTGYOsZh.d.mts} +6 -6
  50. package/dist/{as-table-actions.vue-CTC9xl5i.d.mts → as-table-actions.vue-WXkllHVw.d.cts} +6 -6
  51. package/dist/{as-table-base-DImVUSKt.cjs → as-table-base-1uBBmFuL.cjs} +2 -2
  52. package/dist/{as-table-base-D4Otzbe4.mjs → as-table-base-DOvVedJg.mjs} +2 -2
  53. package/dist/{as-table-header-cell-BEwpWr4m.cjs → as-table-header-cell-DD6Tw87_.cjs} +1 -1
  54. package/dist/{as-table-header-cell-mCOAZsjL.mjs → as-table-header-cell-DfjfNeq4.mjs} +1 -1
  55. package/dist/as-table-header-cell.cjs +1 -1
  56. package/dist/as-table-header-cell.d.cts +1 -1
  57. package/dist/as-table-header-cell.d.mts +1 -1
  58. package/dist/as-table-header-cell.mjs +1 -1
  59. package/dist/{as-table-header-cell.vue-DsVfhlk3.d.mts → as-table-header-cell.vue-BCszzxtU.d.mts} +1 -1
  60. package/dist/{as-table-header-cell.vue-jvtDmqhR.d.cts → as-table-header-cell.vue-BzTzfGRo.d.cts} +1 -1
  61. package/dist/{as-table-root-BQNXfIvB.mjs → as-table-root-BSbO16CM.mjs} +25 -4
  62. package/dist/{as-table-root-BNJ1yqaD.cjs → as-table-root-BnW1SL4W.cjs} +25 -4
  63. package/dist/as-table-root.cjs +1 -1
  64. package/dist/as-table-root.d.cts +1 -1
  65. package/dist/as-table-root.d.mts +1 -1
  66. package/dist/as-table-root.mjs +1 -1
  67. package/dist/{as-table-root.vue-DFCZwH1h.d.cts → as-table-root.vue-DRv85M1N.d.cts} +58 -2
  68. package/dist/{as-table-root.vue-C5IrebWr.d.mts → as-table-root.vue-TUauKr31.d.mts} +58 -2
  69. package/dist/{as-table-status-C3A1WYwb.cjs → as-table-status-2eUIHBmk.cjs} +4 -4
  70. package/dist/{as-table-status-CxkiQ_EE.mjs → as-table-status-Dy3rA0T-.mjs} +4 -4
  71. package/dist/as-table.cjs +1 -1
  72. package/dist/as-table.d.cts +1 -1
  73. package/dist/as-table.d.mts +1 -1
  74. package/dist/as-table.mjs +1 -1
  75. package/dist/{as-table.vue-CAydq1n0.d.mts → as-table.vue-B2ywpIo_.d.mts} +7 -7
  76. package/dist/{as-table.vue-COtIbUsp.d.cts → as-table.vue-Co8kYS_o.d.cts} +7 -7
  77. package/dist/{as-window-table-DONQh4nM.mjs → as-window-table-B9k_nv4c.mjs} +2 -2
  78. package/dist/{as-window-table-BBtgpJ1h.cjs → as-window-table-iwpsLq0K.cjs} +2 -2
  79. package/dist/as-window-table.cjs +1 -1
  80. package/dist/as-window-table.d.cts +1 -1
  81. package/dist/as-window-table.d.mts +1 -1
  82. package/dist/as-window-table.mjs +1 -1
  83. package/dist/{as-window-table.vue-BycvdZ82.d.mts → as-window-table.vue-0ykWW1_K.d.mts} +6 -6
  84. package/dist/{as-window-table.vue-iLK4PSW_.d.cts → as-window-table.vue-DajUEg5q.d.cts} +6 -6
  85. package/dist/index.cjs +17 -17
  86. package/dist/index.d.cts +7 -7
  87. package/dist/index.d.mts +7 -7
  88. package/dist/index.mjs +17 -17
  89. package/dist/{types-BMvxn9iU.d.mts → types-ByU4O0Yf.d.mts} +18 -0
  90. package/dist/{types-CDJmLD-E.d.cts → types-CTMxE_zA.d.cts} +18 -0
  91. package/dist/{use-table-CaegBdPZ.cjs → use-table-BWgcmQS7.cjs} +5 -2
  92. package/dist/{use-table-CGxkBszK.mjs → use-table-DHN_frAf.mjs} +5 -2
  93. package/dist/{use-table-component-ClgvnuRH.mjs → use-table-component-Bu7CIG5I.mjs} +1 -1
  94. package/dist/{use-table-component-D-1kzctZ.cjs → use-table-component-QDcfYIBU.cjs} +1 -1
  95. package/dist/{use-table-nav-bridge-bZIH2d6Y.cjs → use-table-nav-bridge-BlqeY53w.cjs} +1 -1
  96. package/dist/{use-table-nav-bridge-C3gqHOIa.mjs → use-table-nav-bridge-CVO5_ttZ.mjs} +1 -1
  97. package/dist/{use-table-state-152Ejpyo.cjs → use-table-state-CElgF_iy.cjs} +139 -5
  98. package/dist/{use-table-state-BHAwfUKw.mjs → use-table-state-Dju5bxt8.mjs} +116 -6
  99. package/package.json +4 -4
@@ -1,4 +1,4 @@
1
- require("@atscript/ui");
1
+ let _atscript_ui = require("@atscript/ui");
2
2
  let vue = require("vue");
3
3
  let _atscript_ui_table = require("@atscript/ui-table");
4
4
  let _atscript_db_client = require("@atscript/db-client");
@@ -180,6 +180,75 @@ function intentClass(prefix, action) {
180
180
  return action.intent ? `${prefix}-intent-${action.intent}` : void 0;
181
181
  }
182
182
  /**
183
+ * `true` for an unmodified main-button click — the only click an anchor-mode
184
+ * navigate action intercepts (preventDefault + SPA invoke path). Modified /
185
+ * middle / right clicks fall through to native anchor behaviour. Mirrors
186
+ * vue-router's `guardEvent`, including the bail on an already-handled event.
187
+ */
188
+ function isPlainLeftClick(e) {
189
+ return !e.defaultPrevented && e.button === 0 && !e.ctrlKey && !e.metaKey && !e.shiftKey && !e.altKey;
190
+ }
191
+ /** `true` for the "open in new tab" chord on a button: cmd/ctrl + main-button click. */
192
+ function isModClick(e) {
193
+ return e.button === 0 && (e.ctrlKey || e.metaKey);
194
+ }
195
+ /**
196
+ * Render-time href for a `processor: 'navigate'` action, mapped through
197
+ * `state.resolveHref`. Returns `undefined` when no link is possible —
198
+ * non-navigate processors, actions with an `inputForm` (the dialog IS the
199
+ * interaction), or a row-level action without a computable identifier — so
200
+ * callers keep the plain button + invoke path. Actions WITH `promptText`
201
+ * still get their href (the button's mod/middle-click new-tab path needs
202
+ * it); whether to render an anchor is the call site's `promptText` check.
203
+ */
204
+ function actionHref(state, action, id) {
205
+ if (action.processor !== "navigate" || action.inputForm) return void 0;
206
+ const href = (0, _atscript_ui.navigateHrefFor)(action, id, state.tableDef.value?.preferredId ?? []);
207
+ return href === void 0 ? void 0 : state.resolveHref(href);
208
+ }
209
+ /**
210
+ * "Open in new tab" path for navigate actions: run the action's confirmation
211
+ * (immediate accept when it declares no `promptText`), then hand the already
212
+ * `resolveHref`-mapped `href` to the browser via `window.open`. Never touches
213
+ * `state.actions.invoke` and never reaches the `@action` emit — the browser
214
+ * owns the navigation.
215
+ */
216
+ async function openNavigateInNewTab(state, action, ctx, href) {
217
+ if (!await confirmAction(state, action, ctx)) return;
218
+ window.open(href, "_blank", "noopener,noreferrer");
219
+ }
220
+ /**
221
+ * Gesture handler set for the primary trigger (single CTA anchor/button)
222
+ * shared by `<AsRowActions>` and `<AsTableActions>`. Parameterized only by
223
+ * the surface's prompt-context getter and href resolver so the click-dispatch
224
+ * policy — plain left → SPA invoke, cmd/ctrl or middle on a promptText
225
+ * navigate button → confirm → new tab — has a single home.
226
+ */
227
+ function createNavigateGestures(state, promptCtx, hrefFor) {
228
+ return {
229
+ onTriggerClick(action, href, asLink, event) {
230
+ if (asLink) {
231
+ if (!isPlainLeftClick(event)) return;
232
+ event.preventDefault();
233
+ } else if (href !== void 0 && isModClick(event)) {
234
+ openNavigateInNewTab(state, action, promptCtx(), href);
235
+ return;
236
+ }
237
+ triggerAction(state, action, promptCtx(), event);
238
+ },
239
+ onTriggerAuxClick(action, href, asLink, event) {
240
+ if (asLink || href === void 0 || event.button !== 1) return;
241
+ event.preventDefault();
242
+ openNavigateInNewTab(state, action, promptCtx(), href);
243
+ },
244
+ openNewTab(action) {
245
+ const href = hrefFor(action);
246
+ if (href === void 0) return;
247
+ openNavigateInNewTab(state, action, promptCtx(), href);
248
+ }
249
+ };
250
+ }
251
+ /**
183
252
  * Run `state.prompt()` if the action declares a `promptText`. Resolves
184
253
  * `true` on accept, or `true` immediately when no prompt is needed.
185
254
  *
@@ -1264,6 +1333,19 @@ function createTableState(opts) {
1264
1333
  }
1265
1334
  const mustRefresh = (0, vue.ref)(false);
1266
1335
  const searchTerm = (0, vue.ref)("");
1336
+ const ignoreSortersDefault = modelOpts?.ignoreSortersWhenSearched?.value ?? queryOpts?.ignoreSortersWhenSearched ?? false;
1337
+ const ignoreSortersWhenSearched = modelOpts?.ignoreSortersWhenSearched ?? (0, vue.ref)(ignoreSortersDefault);
1338
+ let internalIgnoreSortersWrite = false;
1339
+ function setIgnoreSortersInternal(v) {
1340
+ if (ignoreSortersWhenSearched.value === v) return;
1341
+ if (!internalIgnoreSortersWrite) {
1342
+ internalIgnoreSortersWrite = true;
1343
+ (0, vue.nextTick)(() => {
1344
+ internalIgnoreSortersWrite = false;
1345
+ });
1346
+ }
1347
+ ignoreSortersWhenSearched.value = v;
1348
+ }
1267
1349
  const configDialogOpen = (0, vue.ref)(false);
1268
1350
  const configTab = (0, vue.ref)("columns");
1269
1351
  const filterDialogColumn = (0, vue.ref)(null);
@@ -1325,6 +1407,7 @@ function createTableState(opts) {
1325
1407
  filters: filters.value,
1326
1408
  forceFilters: queryOpts?.forceFilters,
1327
1409
  search: searchTerm.value || void 0,
1410
+ ignoreSorters: ignoreSortersWhenSearched.value && !!searchTerm.value,
1328
1411
  includeActions: includeActions.value
1329
1412
  });
1330
1413
  }
@@ -1510,12 +1593,14 @@ function createTableState(opts) {
1510
1593
  lastError,
1511
1594
  mustRefresh,
1512
1595
  searchTerm,
1596
+ ignoreSortersWhenSearched,
1513
1597
  configDialogOpen,
1514
1598
  configTab,
1515
1599
  filterDialogColumn,
1516
1600
  selectedRows,
1517
1601
  selectedCount,
1518
1602
  rowValueFn,
1603
+ resolveHref: opts.actions?.resolveHref ?? ((url) => url),
1519
1604
  isPkSelected,
1520
1605
  rowDelete,
1521
1606
  includeActions,
@@ -1603,9 +1688,11 @@ function createTableState(opts) {
1603
1688
  sorters: sorters.value,
1604
1689
  page: pagination.value.page,
1605
1690
  itemsPerPage: pagination.value.itemsPerPage,
1606
- searchTerm: searchTerm.value
1691
+ searchTerm: searchTerm.value,
1692
+ ignoreSorters: ignoreSortersWhenSearched.value
1607
1693
  }, {
1608
1694
  defaultItemsPerPage: urlDefaultItemsPerPage,
1695
+ defaultIgnoreSorters: ignoreSortersDefault,
1609
1696
  sync: urlQuerySync
1610
1697
  });
1611
1698
  }
@@ -1644,15 +1731,25 @@ function createTableState(opts) {
1644
1731
  for (const path in parsed.filters) next[path] = parsed.filters[path];
1645
1732
  filters.value = next;
1646
1733
  }
1647
- if ((0, _atscript_ui_table.resolveAspectGate)(urlQuerySync?.sorters) !== "none") {
1734
+ const sortersGate = (0, _atscript_ui_table.resolveAspectGate)(urlQuerySync?.sorters);
1735
+ let urlSortersChanged = false;
1736
+ if (sortersGate !== "none") {
1648
1737
  const urlFields = /* @__PURE__ */ new Set();
1649
1738
  for (const s of parsed.sorters) urlFields.add(s.field);
1650
1739
  const merged = [...sorters.value.filter((s) => !urlFields.has(s.field)), ...parsed.sorters];
1651
- if (!(0, _atscript_ui_table.sortersEqual)(sorters.value, merged)) sorters.value = merged;
1740
+ if (!(0, _atscript_ui_table.sortersEqual)(sorters.value, merged)) {
1741
+ sorters.value = merged;
1742
+ urlSortersChanged = true;
1743
+ }
1652
1744
  }
1745
+ const searchWasActive = !!searchTerm.value;
1653
1746
  if (urlQuerySync?.search !== false) {
1654
1747
  if (searchTerm.value !== parsed.searchTerm) searchTerm.value = parsed.searchTerm;
1655
1748
  }
1749
+ const searchNowActive = !!searchTerm.value;
1750
+ if (!searchWasActive && searchNowActive) setIgnoreSortersInternal(ignoreSortersDefault);
1751
+ else if (urlSortersChanged && searchWasActive && searchNowActive) setIgnoreSortersInternal(false);
1752
+ if (parsed.ignoreSorters !== void 0) setIgnoreSortersInternal(parsed.ignoreSorters);
1656
1753
  if (urlQuerySync?.pagination !== false) {
1657
1754
  if (pagination.value.page !== nextPage) pagination.value = {
1658
1755
  ...pagination.value,
@@ -1688,9 +1785,21 @@ function createTableState(opts) {
1688
1785
  (0, vue.watch)(() => sorters.value, (next, prev) => {
1689
1786
  if (hydratingFromUrl) return;
1690
1787
  if ((0, _atscript_ui_table.sortersEqual)(prev, next)) return;
1788
+ if (searchTerm.value) setIgnoreSortersInternal(false);
1691
1789
  if (!queryDetected) return;
1692
1790
  requestRefresh();
1693
1791
  }, { immediate: false });
1792
+ (0, vue.watch)(() => searchTerm.value, (next, prev) => {
1793
+ if (hydratingFromUrl) return;
1794
+ if (!prev && next) setIgnoreSortersInternal(ignoreSortersDefault);
1795
+ });
1796
+ (0, vue.watch)(() => ignoreSortersWhenSearched.value, () => {
1797
+ if (internalIgnoreSortersWrite) return;
1798
+ if (hydratingFromUrl) return;
1799
+ if (!queryDetected) return;
1800
+ if (!searchTerm.value) return;
1801
+ requestRefresh();
1802
+ });
1694
1803
  (0, vue.watch)(() => columnNames.value, (next, prev) => {
1695
1804
  if (!queryDetected) return;
1696
1805
  if ((0, _atscript_ui_table.sameColumnSet)(prev, next)) return;
@@ -1710,7 +1819,8 @@ function createTableState(opts) {
1710
1819
  () => filters.value,
1711
1820
  () => sorters.value,
1712
1821
  () => searchTerm.value,
1713
- () => pagination.value
1822
+ () => pagination.value,
1823
+ () => ignoreSortersWhenSearched.value
1714
1824
  ], () => emitUrlIfChanged());
1715
1825
  (0, vue.watch)(() => includeActions.value, () => {
1716
1826
  if (!queryDetected) return;
@@ -1894,6 +2004,12 @@ Object.defineProperty(exports, "ROW_ACTIONS_TYPE", {
1894
2004
  return ROW_ACTIONS_TYPE;
1895
2005
  }
1896
2006
  });
2007
+ Object.defineProperty(exports, "actionHref", {
2008
+ enumerable: true,
2009
+ get: function() {
2010
+ return actionHref;
2011
+ }
2012
+ });
1897
2013
  Object.defineProperty(exports, "applyRowGate", {
1898
2014
  enumerable: true,
1899
2015
  get: function() {
@@ -1918,6 +2034,12 @@ Object.defineProperty(exports, "collectIdentifiers", {
1918
2034
  return collectIdentifiers;
1919
2035
  }
1920
2036
  });
2037
+ Object.defineProperty(exports, "createNavigateGestures", {
2038
+ enumerable: true,
2039
+ get: function() {
2040
+ return createNavigateGestures;
2041
+ }
2042
+ });
1921
2043
  Object.defineProperty(exports, "createStaticTableState", {
1922
2044
  enumerable: true,
1923
2045
  get: function() {
@@ -1948,6 +2070,18 @@ Object.defineProperty(exports, "intentToScope", {
1948
2070
  return intentToScope;
1949
2071
  }
1950
2072
  });
2073
+ Object.defineProperty(exports, "isModClick", {
2074
+ enumerable: true,
2075
+ get: function() {
2076
+ return isModClick;
2077
+ }
2078
+ });
2079
+ Object.defineProperty(exports, "isPlainLeftClick", {
2080
+ enumerable: true,
2081
+ get: function() {
2082
+ return isPlainLeftClick;
2083
+ }
2084
+ });
1951
2085
  Object.defineProperty(exports, "provideTableContext", {
1952
2086
  enumerable: true,
1953
2087
  get: function() {
@@ -1,4 +1,4 @@
1
- import "@atscript/ui";
1
+ import { navigateHrefFor } from "@atscript/ui";
2
2
  import { computed, inject, nextTick, onBeforeUnmount, onScopeDispose, provide, ref, shallowRef, toValue, watch } from "vue";
3
3
  import { STANDARD_PRESET_ID, blockStartFor, buildTableQuery, debounce, fromWireSnapshot, isDirtyAgainst, isFilled, isSystemPresetId, pageAlignedBlocksFor, planFetch, reconcileColumnWidthDefaults, resolveAspectGate, resolveSystemPresets, sameColumnSet, sortersEqual, stateToUrlQueryString, togglePk, urlQueryStringToState, walkBackwardAbsorb, walkForwardAbsorb } from "@atscript/ui-table";
4
4
  import { formatIdentifier } from "@atscript/db-client";
@@ -180,6 +180,75 @@ function intentClass(prefix, action) {
180
180
  return action.intent ? `${prefix}-intent-${action.intent}` : void 0;
181
181
  }
182
182
  /**
183
+ * `true` for an unmodified main-button click — the only click an anchor-mode
184
+ * navigate action intercepts (preventDefault + SPA invoke path). Modified /
185
+ * middle / right clicks fall through to native anchor behaviour. Mirrors
186
+ * vue-router's `guardEvent`, including the bail on an already-handled event.
187
+ */
188
+ function isPlainLeftClick(e) {
189
+ return !e.defaultPrevented && e.button === 0 && !e.ctrlKey && !e.metaKey && !e.shiftKey && !e.altKey;
190
+ }
191
+ /** `true` for the "open in new tab" chord on a button: cmd/ctrl + main-button click. */
192
+ function isModClick(e) {
193
+ return e.button === 0 && (e.ctrlKey || e.metaKey);
194
+ }
195
+ /**
196
+ * Render-time href for a `processor: 'navigate'` action, mapped through
197
+ * `state.resolveHref`. Returns `undefined` when no link is possible —
198
+ * non-navigate processors, actions with an `inputForm` (the dialog IS the
199
+ * interaction), or a row-level action without a computable identifier — so
200
+ * callers keep the plain button + invoke path. Actions WITH `promptText`
201
+ * still get their href (the button's mod/middle-click new-tab path needs
202
+ * it); whether to render an anchor is the call site's `promptText` check.
203
+ */
204
+ function actionHref(state, action, id) {
205
+ if (action.processor !== "navigate" || action.inputForm) return void 0;
206
+ const href = navigateHrefFor(action, id, state.tableDef.value?.preferredId ?? []);
207
+ return href === void 0 ? void 0 : state.resolveHref(href);
208
+ }
209
+ /**
210
+ * "Open in new tab" path for navigate actions: run the action's confirmation
211
+ * (immediate accept when it declares no `promptText`), then hand the already
212
+ * `resolveHref`-mapped `href` to the browser via `window.open`. Never touches
213
+ * `state.actions.invoke` and never reaches the `@action` emit — the browser
214
+ * owns the navigation.
215
+ */
216
+ async function openNavigateInNewTab(state, action, ctx, href) {
217
+ if (!await confirmAction(state, action, ctx)) return;
218
+ window.open(href, "_blank", "noopener,noreferrer");
219
+ }
220
+ /**
221
+ * Gesture handler set for the primary trigger (single CTA anchor/button)
222
+ * shared by `<AsRowActions>` and `<AsTableActions>`. Parameterized only by
223
+ * the surface's prompt-context getter and href resolver so the click-dispatch
224
+ * policy — plain left → SPA invoke, cmd/ctrl or middle on a promptText
225
+ * navigate button → confirm → new tab — has a single home.
226
+ */
227
+ function createNavigateGestures(state, promptCtx, hrefFor) {
228
+ return {
229
+ onTriggerClick(action, href, asLink, event) {
230
+ if (asLink) {
231
+ if (!isPlainLeftClick(event)) return;
232
+ event.preventDefault();
233
+ } else if (href !== void 0 && isModClick(event)) {
234
+ openNavigateInNewTab(state, action, promptCtx(), href);
235
+ return;
236
+ }
237
+ triggerAction(state, action, promptCtx(), event);
238
+ },
239
+ onTriggerAuxClick(action, href, asLink, event) {
240
+ if (asLink || href === void 0 || event.button !== 1) return;
241
+ event.preventDefault();
242
+ openNavigateInNewTab(state, action, promptCtx(), href);
243
+ },
244
+ openNewTab(action) {
245
+ const href = hrefFor(action);
246
+ if (href === void 0) return;
247
+ openNavigateInNewTab(state, action, promptCtx(), href);
248
+ }
249
+ };
250
+ }
251
+ /**
183
252
  * Run `state.prompt()` if the action declares a `promptText`. Resolves
184
253
  * `true` on accept, or `true` immediately when no prompt is needed.
185
254
  *
@@ -1264,6 +1333,19 @@ function createTableState(opts) {
1264
1333
  }
1265
1334
  const mustRefresh = ref(false);
1266
1335
  const searchTerm = ref("");
1336
+ const ignoreSortersDefault = modelOpts?.ignoreSortersWhenSearched?.value ?? queryOpts?.ignoreSortersWhenSearched ?? false;
1337
+ const ignoreSortersWhenSearched = modelOpts?.ignoreSortersWhenSearched ?? ref(ignoreSortersDefault);
1338
+ let internalIgnoreSortersWrite = false;
1339
+ function setIgnoreSortersInternal(v) {
1340
+ if (ignoreSortersWhenSearched.value === v) return;
1341
+ if (!internalIgnoreSortersWrite) {
1342
+ internalIgnoreSortersWrite = true;
1343
+ nextTick(() => {
1344
+ internalIgnoreSortersWrite = false;
1345
+ });
1346
+ }
1347
+ ignoreSortersWhenSearched.value = v;
1348
+ }
1267
1349
  const configDialogOpen = ref(false);
1268
1350
  const configTab = ref("columns");
1269
1351
  const filterDialogColumn = ref(null);
@@ -1325,6 +1407,7 @@ function createTableState(opts) {
1325
1407
  filters: filters.value,
1326
1408
  forceFilters: queryOpts?.forceFilters,
1327
1409
  search: searchTerm.value || void 0,
1410
+ ignoreSorters: ignoreSortersWhenSearched.value && !!searchTerm.value,
1328
1411
  includeActions: includeActions.value
1329
1412
  });
1330
1413
  }
@@ -1510,12 +1593,14 @@ function createTableState(opts) {
1510
1593
  lastError,
1511
1594
  mustRefresh,
1512
1595
  searchTerm,
1596
+ ignoreSortersWhenSearched,
1513
1597
  configDialogOpen,
1514
1598
  configTab,
1515
1599
  filterDialogColumn,
1516
1600
  selectedRows,
1517
1601
  selectedCount,
1518
1602
  rowValueFn,
1603
+ resolveHref: opts.actions?.resolveHref ?? ((url) => url),
1519
1604
  isPkSelected,
1520
1605
  rowDelete,
1521
1606
  includeActions,
@@ -1603,9 +1688,11 @@ function createTableState(opts) {
1603
1688
  sorters: sorters.value,
1604
1689
  page: pagination.value.page,
1605
1690
  itemsPerPage: pagination.value.itemsPerPage,
1606
- searchTerm: searchTerm.value
1691
+ searchTerm: searchTerm.value,
1692
+ ignoreSorters: ignoreSortersWhenSearched.value
1607
1693
  }, {
1608
1694
  defaultItemsPerPage: urlDefaultItemsPerPage,
1695
+ defaultIgnoreSorters: ignoreSortersDefault,
1609
1696
  sync: urlQuerySync
1610
1697
  });
1611
1698
  }
@@ -1644,15 +1731,25 @@ function createTableState(opts) {
1644
1731
  for (const path in parsed.filters) next[path] = parsed.filters[path];
1645
1732
  filters.value = next;
1646
1733
  }
1647
- if (resolveAspectGate(urlQuerySync?.sorters) !== "none") {
1734
+ const sortersGate = resolveAspectGate(urlQuerySync?.sorters);
1735
+ let urlSortersChanged = false;
1736
+ if (sortersGate !== "none") {
1648
1737
  const urlFields = /* @__PURE__ */ new Set();
1649
1738
  for (const s of parsed.sorters) urlFields.add(s.field);
1650
1739
  const merged = [...sorters.value.filter((s) => !urlFields.has(s.field)), ...parsed.sorters];
1651
- if (!sortersEqual(sorters.value, merged)) sorters.value = merged;
1740
+ if (!sortersEqual(sorters.value, merged)) {
1741
+ sorters.value = merged;
1742
+ urlSortersChanged = true;
1743
+ }
1652
1744
  }
1745
+ const searchWasActive = !!searchTerm.value;
1653
1746
  if (urlQuerySync?.search !== false) {
1654
1747
  if (searchTerm.value !== parsed.searchTerm) searchTerm.value = parsed.searchTerm;
1655
1748
  }
1749
+ const searchNowActive = !!searchTerm.value;
1750
+ if (!searchWasActive && searchNowActive) setIgnoreSortersInternal(ignoreSortersDefault);
1751
+ else if (urlSortersChanged && searchWasActive && searchNowActive) setIgnoreSortersInternal(false);
1752
+ if (parsed.ignoreSorters !== void 0) setIgnoreSortersInternal(parsed.ignoreSorters);
1656
1753
  if (urlQuerySync?.pagination !== false) {
1657
1754
  if (pagination.value.page !== nextPage) pagination.value = {
1658
1755
  ...pagination.value,
@@ -1688,9 +1785,21 @@ function createTableState(opts) {
1688
1785
  watch(() => sorters.value, (next, prev) => {
1689
1786
  if (hydratingFromUrl) return;
1690
1787
  if (sortersEqual(prev, next)) return;
1788
+ if (searchTerm.value) setIgnoreSortersInternal(false);
1691
1789
  if (!queryDetected) return;
1692
1790
  requestRefresh();
1693
1791
  }, { immediate: false });
1792
+ watch(() => searchTerm.value, (next, prev) => {
1793
+ if (hydratingFromUrl) return;
1794
+ if (!prev && next) setIgnoreSortersInternal(ignoreSortersDefault);
1795
+ });
1796
+ watch(() => ignoreSortersWhenSearched.value, () => {
1797
+ if (internalIgnoreSortersWrite) return;
1798
+ if (hydratingFromUrl) return;
1799
+ if (!queryDetected) return;
1800
+ if (!searchTerm.value) return;
1801
+ requestRefresh();
1802
+ });
1694
1803
  watch(() => columnNames.value, (next, prev) => {
1695
1804
  if (!queryDetected) return;
1696
1805
  if (sameColumnSet(prev, next)) return;
@@ -1710,7 +1819,8 @@ function createTableState(opts) {
1710
1819
  () => filters.value,
1711
1820
  () => sorters.value,
1712
1821
  () => searchTerm.value,
1713
- () => pagination.value
1822
+ () => pagination.value,
1823
+ () => ignoreSortersWhenSearched.value
1714
1824
  ], () => emitUrlIfChanged());
1715
1825
  watch(() => includeActions.value, () => {
1716
1826
  if (!queryDetected) return;
@@ -1876,4 +1986,4 @@ function useRegisterMainActionListener(state, listener, enabled) {
1876
1986
  });
1877
1987
  }
1878
1988
  //#endregion
1879
- export { ROW_ACTIONS_TYPE as _, useTableContext as a, applyRowGate as c, collectIdentifiers as d, extractIdentifier as f, ROW_ACTIONS_PATH as g, triggerAction as h, useRegisterMainActionListener as i, applyRowsGate as l, intentToScope as m, createTableState as n, useTableContextOptional as o, intentClass as p, provideTableContext as r, DEFAULT_AVAILABLE_ASPECTS as s, createStaticTableState as t, ariaLabelFor as u };
1989
+ export { isModClick as _, useTableContext as a, ROW_ACTIONS_PATH as b, actionHref as c, ariaLabelFor as d, collectIdentifiers as f, intentToScope as g, intentClass as h, useRegisterMainActionListener as i, applyRowGate as l, extractIdentifier as m, createTableState as n, useTableContextOptional as o, createNavigateGestures as p, provideTableContext as r, DEFAULT_AVAILABLE_ASPECTS as s, createStaticTableState as t, applyRowsGate as u, isPlainLeftClick as v, ROW_ACTIONS_TYPE as x, triggerAction as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/vue-table",
3
- "version": "0.1.111",
3
+ "version": "0.1.113",
4
4
  "description": "Type-driven table components for Atscript with Vue 3",
5
5
  "keywords": [
6
6
  "atscript",
@@ -162,9 +162,9 @@
162
162
  "access": "public"
163
163
  },
164
164
  "dependencies": {
165
- "@atscript/ui": "^0.1.111",
166
- "@atscript/vue-form": "^0.1.111",
167
- "@atscript/ui-table": "^0.1.111"
165
+ "@atscript/ui": "^0.1.113",
166
+ "@atscript/vue-form": "^0.1.113",
167
+ "@atscript/ui-table": "^0.1.113"
168
168
  },
169
169
  "devDependencies": {
170
170
  "@atscript/db-client": "^0.1.111",