@atscript/vue-table 0.1.97 → 0.1.98

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 (177) 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-cell-array-DOQKR6t5.mjs → as-cell-array-2qmJ1lT2.mjs} +2 -2
  4. package/dist/{as-cell-array-CXeZzZqt.cjs → as-cell-array-iPeUnk2G.cjs} +2 -2
  5. package/dist/as-cell-array.cjs +1 -1
  6. package/dist/as-cell-array.d.mts +1 -1
  7. package/dist/as-cell-array.mjs +1 -1
  8. package/dist/{as-cell-date-DPWBlhyM.mjs → as-cell-date-BwFgi6O0.mjs} +2 -2
  9. package/dist/{as-cell-date-D0rowX5E.cjs → as-cell-date-DyixWKuS.cjs} +2 -2
  10. package/dist/as-cell-date.cjs +1 -1
  11. package/dist/as-cell-date.d.mts +1 -1
  12. package/dist/as-cell-date.mjs +1 -1
  13. package/dist/{as-cell-json-BynWIs1d.mjs → as-cell-json--95Xq6yq.mjs} +2 -2
  14. package/dist/{as-cell-json-DvHvQ6IL.cjs → as-cell-json-Bvv2P7YV.cjs} +2 -2
  15. package/dist/as-cell-json.cjs +1 -1
  16. package/dist/as-cell-json.d.mts +1 -1
  17. package/dist/as-cell-json.mjs +1 -1
  18. package/dist/{as-cell-number-Bc1C97Vg.mjs → as-cell-number-DKRaS9pM.mjs} +2 -2
  19. package/dist/{as-cell-number-0_WrSCzu.cjs → as-cell-number-DuPMOesI.cjs} +2 -2
  20. package/dist/as-cell-number.cjs +1 -1
  21. package/dist/as-cell-number.d.mts +1 -1
  22. package/dist/as-cell-number.mjs +1 -1
  23. package/dist/{as-cell-union-CFAI0utz.cjs → as-cell-union-CT0rIvQq.cjs} +3 -3
  24. package/dist/{as-cell-union-C1w3B38J.mjs → as-cell-union-sAOSdepj.mjs} +3 -3
  25. package/dist/as-cell-union.cjs +1 -1
  26. package/dist/as-cell-union.d.mts +1 -1
  27. package/dist/as-cell-union.mjs +1 -1
  28. package/dist/as-column-menu.cjs +1 -1
  29. package/dist/as-column-menu.d.cts +1 -1
  30. package/dist/as-column-menu.d.mts +1 -1
  31. package/dist/as-column-menu.mjs +1 -1
  32. package/dist/{as-column-menu.vue-C9e6wJ3z.d.mts → as-column-menu.vue-BtXVQywl.d.cts} +2 -2
  33. package/dist/{as-column-menu.vue-o0qFdzoL.d.cts → as-column-menu.vue-D3Z5BVLx.d.mts} +2 -2
  34. package/dist/{as-config-dialog-BB6BDa1E.mjs → as-config-dialog-COwDabdW.mjs} +15 -13
  35. package/dist/{as-config-dialog-BCvtSxi6.cjs → as-config-dialog-vOUtx5zq.cjs} +14 -12
  36. package/dist/as-config-dialog.cjs +1 -1
  37. package/dist/as-config-dialog.d.mts +1 -1
  38. package/dist/as-config-dialog.mjs +1 -1
  39. package/dist/as-confirm-dialog.cjs +1 -1
  40. package/dist/as-confirm-dialog.d.mts +1 -1
  41. package/dist/as-confirm-dialog.mjs +1 -1
  42. package/dist/{as-filter-dialog-O62-CnIQ.cjs → as-filter-dialog-BcPI27cn.cjs} +19 -70
  43. package/dist/{as-filter-dialog-KGyPqr2P.mjs → as-filter-dialog-DuFgEjqE.mjs} +20 -65
  44. package/dist/as-filter-dialog.cjs +1 -1
  45. package/dist/as-filter-dialog.d.mts +1 -1
  46. package/dist/as-filter-dialog.mjs +1 -1
  47. package/dist/{as-filter-field-jL7cnKUR.cjs → as-filter-field-B8idz2UD.cjs} +3 -473
  48. package/dist/{as-filter-field-CkiRXHVx.mjs → as-filter-field-Dsk1l3Et.mjs} +7 -441
  49. package/dist/as-filter-field.cjs +1 -1
  50. package/dist/as-filter-field.d.mts +1 -1
  51. package/dist/as-filter-field.mjs +1 -1
  52. package/dist/as-filter-input.cjs +1 -1
  53. package/dist/as-filter-input.d.mts +1 -1
  54. package/dist/as-filter-input.mjs +1 -1
  55. package/dist/{as-filters-BJM-NjUn.mjs → as-filters-BS7kWJfI.mjs} +5 -3
  56. package/dist/{as-filters-BFpZKtAU.cjs → as-filters-BzdQ4HUx.cjs} +4 -2
  57. package/dist/as-filters.cjs +1 -1
  58. package/dist/as-filters.d.mts +1 -1
  59. package/dist/as-filters.mjs +1 -1
  60. package/dist/{as-preset-dialog-1Xl8DIiN.cjs → as-preset-dialog-DOdrDDKy.cjs} +7 -8
  61. package/dist/{as-preset-dialog-DXbqMVI1.mjs → as-preset-dialog-DoEpCt2j.mjs} +7 -8
  62. package/dist/as-preset-dialog.cjs +1 -1
  63. package/dist/as-preset-dialog.d.mts +1 -1
  64. package/dist/as-preset-dialog.mjs +1 -1
  65. package/dist/{as-preset-picker-CkaaKzYB.cjs → as-preset-picker-2DkH7QfW.cjs} +1 -1
  66. package/dist/{as-preset-picker-DJTF47_V.mjs → as-preset-picker-ByUCQpnX.mjs} +1 -1
  67. package/dist/as-preset-picker.cjs +1 -1
  68. package/dist/as-preset-picker.d.mts +1 -1
  69. package/dist/as-preset-picker.mjs +1 -1
  70. package/dist/{as-row-actions-C78cvaf3.cjs → as-row-actions-05pQX_om.cjs} +1 -1
  71. package/dist/{as-row-actions-CpEMa5NU.mjs → as-row-actions-D7YgGt0x.mjs} +1 -1
  72. package/dist/as-row-actions.cjs +1 -1
  73. package/dist/as-row-actions.d.mts +1 -1
  74. package/dist/as-row-actions.mjs +1 -1
  75. package/dist/{as-table-v42bV1ea.cjs → as-table-DyuL_hUo.cjs} +6 -5
  76. package/dist/{as-table-DDyvnBFL.mjs → as-table-H5uKWieH.mjs} +4 -3
  77. package/dist/{as-table-actions-DtCjMMCI.cjs → as-table-actions-CsdY2_BG.cjs} +1 -1
  78. package/dist/{as-table-actions-D2-MBvoy.mjs → as-table-actions-DCEGQiHi.mjs} +1 -1
  79. package/dist/as-table-actions.cjs +1 -1
  80. package/dist/as-table-actions.d.cts +1 -1
  81. package/dist/as-table-actions.d.mts +1 -1
  82. package/dist/as-table-actions.mjs +1 -1
  83. package/dist/{as-table-actions.vue-pDtCQ0oB.d.cts → as-table-actions.vue-33oeDXOg.d.cts} +2 -2
  84. package/dist/{as-table-actions.vue-riwwEAGF.d.mts → as-table-actions.vue-DMf6-R5o.d.mts} +2 -2
  85. package/dist/{as-table-base-CSrtmIN2.mjs → as-table-base-DReD74pJ.mjs} +2 -2
  86. package/dist/{as-table-base-CHzULili.cjs → as-table-base-GEf95oXP.cjs} +2 -2
  87. package/dist/{as-table-cell-value-B1CiJYFn.mjs → as-table-cell-value-Byrb_Zyh.mjs} +2 -2
  88. package/dist/{as-table-cell-value-CuxRtFn9.cjs → as-table-cell-value-CcWR5oG4.cjs} +2 -2
  89. package/dist/as-table-cell-value.cjs +1 -1
  90. package/dist/as-table-cell-value.d.mts +1 -1
  91. package/dist/as-table-cell-value.mjs +1 -1
  92. package/dist/{as-table-header-cell-CBn_ioCe.mjs → as-table-header-cell-BUf8wvrw.mjs} +6 -4
  93. package/dist/{as-table-header-cell-C3zeZUZo.cjs → as-table-header-cell-DWONx2MI.cjs} +5 -3
  94. package/dist/as-table-header-cell.cjs +1 -1
  95. package/dist/as-table-header-cell.d.cts +1 -1
  96. package/dist/as-table-header-cell.d.mts +1 -1
  97. package/dist/as-table-header-cell.mjs +1 -1
  98. package/dist/{as-table-header-cell.vue-Bc_DSsGY.d.cts → as-table-header-cell.vue-CzqTEpyk.d.cts} +1 -1
  99. package/dist/{as-table-header-cell.vue-DNMOHfek.d.mts → as-table-header-cell.vue-Dj_Tl7dZ.d.mts} +1 -1
  100. package/dist/{as-table-root-zJdmNnsC.cjs → as-table-root-Cg2zkxR5.cjs} +8 -20
  101. package/dist/{as-table-root-Bc23Z7we.mjs → as-table-root-DpQUTbQ8.mjs} +4 -16
  102. package/dist/as-table-root.cjs +1 -1
  103. package/dist/as-table-root.d.cts +1 -1
  104. package/dist/as-table-root.d.mts +1 -1
  105. package/dist/as-table-root.mjs +1 -1
  106. package/dist/{as-table-root.vue-DuMkOgkl.d.mts → as-table-root.vue-Boq6pDr1.d.mts} +13 -4
  107. package/dist/{as-table-root.vue-D3ILISqx.d.cts → as-table-root.vue-CYmnf5SH.d.cts} +13 -4
  108. package/dist/{as-table-status-DKXFSCzE.cjs → as-table-status-DZP8dFpm.cjs} +17 -74
  109. package/dist/{as-table-status-B11orhFu.mjs → as-table-status-Dinns93w.mjs} +19 -64
  110. package/dist/as-table.cjs +1 -1
  111. package/dist/as-table.d.cts +1 -1
  112. package/dist/as-table.d.mts +1 -1
  113. package/dist/as-table.mjs +1 -1
  114. package/dist/{as-table.vue-Bab-ISDO.d.mts → as-table.vue-CE_7OC_h.d.mts} +3 -3
  115. package/dist/{as-table.vue-Dk6YH5ls.d.cts → as-table.vue-kFORh8Vg.d.cts} +3 -3
  116. package/dist/{as-window-table-CDTjX7W5.mjs → as-window-table-BwF2t4Zy.mjs} +5 -3
  117. package/dist/{as-window-table-DuwMCDUh.cjs → as-window-table-CCRJKpoE.cjs} +7 -5
  118. package/dist/as-window-table.cjs +1 -1
  119. package/dist/as-window-table.d.cts +1 -1
  120. package/dist/as-window-table.d.mts +1 -1
  121. package/dist/as-window-table.mjs +1 -1
  122. package/dist/{as-window-table.vue-DjTUqghh.d.mts → as-window-table.vue-C60NtRtq.d.cts} +3 -3
  123. package/dist/{as-window-table.vue-BJFSC4Rq.d.cts → as-window-table.vue-C88OoW5d.d.mts} +3 -3
  124. package/dist/index.cjs +46 -44
  125. package/dist/index.d.cts +19 -17
  126. package/dist/index.d.mts +23 -21
  127. package/dist/index.mjs +35 -35
  128. package/dist/{types-BvvXN72P.d.mts → types-BPFBxUS_.d.cts} +2 -4
  129. package/dist/{types-CNMmF6W2.d.cts → types-BWeFiZKk.d.mts} +2 -4
  130. package/dist/use-has-emit-listener-BTMDIv2e.mjs +14 -0
  131. package/dist/use-has-emit-listener-hhOH8CBI.cjs +19 -0
  132. package/dist/use-seed-on-open-DO3A1kIb.mjs +30 -0
  133. package/dist/use-seed-on-open-Dg9I89fU.cjs +35 -0
  134. package/dist/use-table-CLsp2mAu.cjs +475 -0
  135. package/dist/use-table-CRsFMyJb.mjs +440 -0
  136. package/dist/{use-table-column-handlers-CGYAY2xH.cjs → use-table-column-handlers-BgC4gUJV.cjs} +0 -19
  137. package/dist/{use-table-column-handlers-t6xi1yCE.mjs → use-table-column-handlers-cm0GxR2u.mjs} +1 -14
  138. package/dist/use-table-component-BbETnUuy.mjs +12 -0
  139. package/dist/use-table-component-CirEOQ_P.cjs +17 -0
  140. package/dist/use-table-nav-bridge-Bh1tpG0X.cjs +57 -0
  141. package/dist/use-table-nav-bridge-i8AjtjIt.mjs +52 -0
  142. package/dist/use-table-selection-C84z4OZy.mjs +59 -0
  143. package/dist/use-table-selection-Cmiu1h4S.cjs +70 -0
  144. package/package.json +10 -7
  145. /package/dist/{as-action-menu-content-CSPPMACR.cjs → as-action-menu-content-BChqFX3E.cjs} +0 -0
  146. /package/dist/{as-action-menu-content-DXWuttt_.mjs → as-action-menu-content-D2yf0zD2.mjs} +0 -0
  147. /package/dist/{as-cell-array.vue-DZGM2VHh.d.mts → as-cell-array.vue-D4vS7C_D.d.mts} +0 -0
  148. /package/dist/{as-cell-date.vue-Zlt4mHWb.d.mts → as-cell-date.vue-Chs7WTZ9.d.mts} +0 -0
  149. /package/dist/{as-cell-json-popover-BWdNs1YU.cjs → as-cell-json-popover-BM2QLgfk.cjs} +0 -0
  150. /package/dist/{as-cell-json-popover-DUq25I0L.mjs → as-cell-json-popover-Dkdv5Y9E.mjs} +0 -0
  151. /package/dist/{as-cell-json.vue-CESWuCer.d.mts → as-cell-json.vue-C0_LDvQw.d.mts} +0 -0
  152. /package/dist/{as-cell-number.vue-1Oq7nVI3.d.mts → as-cell-number.vue-BBF0OuU8.d.mts} +0 -0
  153. /package/dist/{as-cell-union.vue-NnDmQZOA.d.mts → as-cell-union.vue-CL-Lf-Rm.d.mts} +0 -0
  154. /package/dist/{as-column-menu-CH9Htz0Q.cjs → as-column-menu-fZVbJ9lU.cjs} +0 -0
  155. /package/dist/{as-column-menu-DCfhorMP.mjs → as-column-menu-kTIQfLTi.mjs} +0 -0
  156. /package/dist/{as-config-dialog.vue-C6Q62xF5.d.mts → as-config-dialog.vue-BvFZZRuY.d.mts} +0 -0
  157. /package/dist/{as-confirm-dialog-Xtw2wE1X.cjs → as-confirm-dialog-C6HAGzrj.cjs} +0 -0
  158. /package/dist/{as-confirm-dialog-DL0mCEeX.mjs → as-confirm-dialog-ClVKU1Dm.mjs} +0 -0
  159. /package/dist/{as-confirm-dialog.vue-pas8jGhv.d.mts → as-confirm-dialog.vue-Cz52-v6c.d.mts} +0 -0
  160. /package/dist/{as-filter-dialog.vue-RDZjp4gJ.d.mts → as-filter-dialog.vue-likNLqzF.d.mts} +0 -0
  161. /package/dist/{as-filter-field.vue-QY8wi5S5.d.mts → as-filter-field.vue-BbXLhd6O.d.mts} +0 -0
  162. /package/dist/{as-filter-input-P1i0CW2-.mjs → as-filter-input-BM23TNeh.mjs} +0 -0
  163. /package/dist/{as-filter-input--nr72iwX.cjs → as-filter-input-DJu2k9gO.cjs} +0 -0
  164. /package/dist/{as-filter-input.vue-CBQ71eNg.d.mts → as-filter-input.vue-B9ma2l9j.d.mts} +0 -0
  165. /package/dist/{as-filters.vue-BsMgYUcX.d.mts → as-filters.vue-DmECMd1v.d.mts} +0 -0
  166. /package/dist/{as-preset-dialog.vue-Bzv-ON9W.d.mts → as-preset-dialog.vue-BRjjfPty.d.mts} +0 -0
  167. /package/dist/{as-preset-picker.vue-CTBk6leV.d.mts → as-preset-picker.vue-BPjsiaVt.d.mts} +0 -0
  168. /package/dist/{as-row-actions.vue-BPaQfGev.d.mts → as-row-actions.vue-DUSDuoR2.d.mts} +0 -0
  169. /package/dist/{as-table-cell-value.vue-BuPCQ8YA.d.mts → as-table-cell-value.vue-kfNgVhzn.d.mts} +0 -0
  170. /package/dist/{format-cell-B2xMDYO9.mjs → format-cell-CNQ6BpvR.mjs} +0 -0
  171. /package/dist/{format-cell-D4mqaN0E.cjs → format-cell-CSbJgz5B.cjs} +0 -0
  172. /package/dist/{get-cell-value-CZSVfDLg.cjs → get-cell-value-4rHKP-TG.cjs} +0 -0
  173. /package/dist/{get-cell-value-DiH84HKL.mjs → get-cell-value-C8LLc_Rr.mjs} +0 -0
  174. /package/dist/{preset-aspect-display-BYeiSgcc.mjs → preset-aspect-display-IICxAlVo.mjs} +0 -0
  175. /package/dist/{preset-aspect-display-y8aal_EF.cjs → preset-aspect-display-TWwf6j1B.cjs} +0 -0
  176. /package/dist/{use-cell-locale-B480_QYK.cjs → use-cell-locale-BGBRQB7s.cjs} +0 -0
  177. /package/dist/{use-cell-locale-1uQaFTLQ.mjs → use-cell-locale-MQXoONh5.mjs} +0 -0
@@ -0,0 +1,440 @@
1
+ import { n as createTableState, r as provideTableContext, s as DEFAULT_AVAILABLE_ASPECTS } from "./use-table-state-CuZ2OXoY.mjs";
2
+ import { n as useTableSelection } from "./use-table-selection-C84z4OZy.mjs";
3
+ import { createTableDef, getMetaEntry, resetMetaCache } from "@atscript/ui";
4
+ import { computed, inject, isRef, ref, shallowRef, watch } from "vue";
5
+ import { PresetsClient, STANDARD_PRESET_ID, debounce, deserializeDraft, isAuthError, isEmptyDraft, isSystemPresetId, resolveSystemPresets, serializeDraft, stableStringify } from "@atscript/ui-table";
6
+ //#region src/composables/as-presets-app.ts
7
+ /**
8
+ * App-wide injection key for the presets system. The host app calls
9
+ * `app.provide(AS_PRESETS_APP, '<your-app>')` once at boot; every
10
+ * `<AsTableRoot>`, `usePresets`, and `useAppPrefs` call below it pulls the
11
+ * value via `inject(AS_PRESETS_APP)` unless an explicit `app` option
12
+ * overrides it.
13
+ *
14
+ * The string identifies the application namespace on the server side —
15
+ * one Moost backend can serve many apps; rows are scoped by `(app,
16
+ * tableKey)`.
17
+ */
18
+ const AS_PRESETS_APP = Symbol("AS_PRESETS_APP");
19
+ /**
20
+ * Resolve the app name with these precedence rules:
21
+ *
22
+ * 1. `explicit` argument (composable option) — wins.
23
+ * 2. `inject(AS_PRESETS_APP)` from the Vue tree.
24
+ * 3. Throws — composable can't run without an app namespace.
25
+ *
26
+ * Throws a clear error when neither is available so misconfiguration
27
+ * surfaces at setup time, not when the first network round-trip fails.
28
+ */
29
+ function injectPresetsApp(explicit) {
30
+ if (explicit && explicit.length > 0) return explicit;
31
+ const fromProvide = inject(AS_PRESETS_APP, void 0);
32
+ if (fromProvide && fromProvide.length > 0) return fromProvide;
33
+ throw new Error("[vue-table] AS_PRESETS_APP not provided. Call `app.provide(AS_PRESETS_APP, '<your-app>')` once at boot, or pass `app` to the composable.");
34
+ }
35
+ //#endregion
36
+ //#region src/composables/use-local-draft.ts
37
+ const DEFAULT_DEBOUNCE_MS = 300;
38
+ /**
39
+ * localStorage overlay manager for table presets. One overlay per
40
+ * `(app, tableKey)`; switching presets clears it (caller's responsibility
41
+ * — this composable only tracks state, not which preset is active).
42
+ */
43
+ function useLocalDraft(opts) {
44
+ const key = `as-table-draft:${opts.app}:${opts.tableKey}`;
45
+ const debounceMs = opts.debounceMs ?? DEFAULT_DEBOUNCE_MS;
46
+ const storage = resolveStorage(opts.storage);
47
+ function isEnabled() {
48
+ if (typeof opts.enabled === "boolean") return opts.enabled;
49
+ if (isRef(opts.enabled)) return Boolean(opts.enabled.value);
50
+ return false;
51
+ }
52
+ function readDraft() {
53
+ if (!storage) return null;
54
+ try {
55
+ const raw = storage.getItem(key);
56
+ if (!raw) return null;
57
+ const parsed = JSON.parse(raw);
58
+ if (!parsed || typeof parsed !== "object") return null;
59
+ return parsed;
60
+ } catch (err) {
61
+ console.warn("[vue-table] useLocalDraft: corrupted localStorage entry, ignoring", err);
62
+ return null;
63
+ }
64
+ }
65
+ function writeDraft(draft) {
66
+ if (!storage) return;
67
+ try {
68
+ storage.setItem(key, JSON.stringify(draft));
69
+ } catch (err) {
70
+ console.warn("[vue-table] useLocalDraft: localStorage write failed", err);
71
+ }
72
+ }
73
+ function clear() {
74
+ if (!storage) return;
75
+ try {
76
+ storage.removeItem(key);
77
+ } catch {}
78
+ }
79
+ function hydrate(applied) {
80
+ if (!isEnabled()) return applied;
81
+ const draft = readDraft();
82
+ if (!draft || isEmptyDraft(draft)) return applied;
83
+ const overlay = deserializeDraft(draft, opts.availableAspects);
84
+ return {
85
+ ...applied,
86
+ ...overlay
87
+ };
88
+ }
89
+ function watchAndPersist(currentSnapshot, activePresetSnapshot) {
90
+ let lastDraftSerialized = "";
91
+ let lastPresetRef = null;
92
+ let lastPresetSerialized = "";
93
+ function flush(current, preset) {
94
+ if (!isEnabled()) return;
95
+ const draft = serializeDraft(current, opts.availableAspects);
96
+ if (isEmptyDraft(draft)) {
97
+ clear();
98
+ lastDraftSerialized = "";
99
+ return;
100
+ }
101
+ const draftSerialized = stableStringify(draft);
102
+ if (preset !== lastPresetRef) {
103
+ lastPresetRef = preset;
104
+ lastPresetSerialized = stableStringify(serializeDraft(preset, opts.availableAspects));
105
+ }
106
+ if (draftSerialized === lastPresetSerialized) {
107
+ clear();
108
+ lastDraftSerialized = "";
109
+ return;
110
+ }
111
+ if (draftSerialized === lastDraftSerialized) return;
112
+ lastDraftSerialized = draftSerialized;
113
+ writeDraft(draft);
114
+ }
115
+ const flushDebounced = debounce(((current, preset) => flush(current, preset)), debounceMs);
116
+ const stop = watch(() => [currentSnapshot(), activePresetSnapshot()], ([current, preset]) => flushDebounced(current, preset), { flush: "post" });
117
+ return () => {
118
+ flushDebounced.cancel();
119
+ stop();
120
+ };
121
+ }
122
+ return {
123
+ hydrate,
124
+ watchAndPersist,
125
+ clear,
126
+ readDraft
127
+ };
128
+ }
129
+ function resolveStorage(provided) {
130
+ if (provided !== void 0) return provided;
131
+ try {
132
+ return globalThis.localStorage ?? null;
133
+ } catch {
134
+ return null;
135
+ }
136
+ }
137
+ //#endregion
138
+ //#region src/composables/use-presets.ts
139
+ /**
140
+ * Public dev-facing composable for table presets. Powers `<AsPresetPicker>`
141
+ * internally and is exported for devs who want to wire bespoke surfaces.
142
+ *
143
+ * Stateful: holds reactive `presets` / `userConf` / `capabilities` and
144
+ * supports optimistic mutators that re-list after each successful write.
145
+ *
146
+ * Active-preset selection (`activePresetId`) is **owned by the caller** —
147
+ * the composable provides the ref but doesn't auto-resolve it on mount;
148
+ * that's the table-state's responsibility (Slice 4) since it depends on
149
+ * `userConf.defaultPresetId` resolution + Standard fallback.
150
+ */
151
+ function usePresets(opts) {
152
+ const app = injectPresetsApp(opts.app);
153
+ if (!opts.tableKey) throw new Error("[vue-table] usePresets: `tableKey` is required");
154
+ const client = new PresetsClient({
155
+ url: opts.url,
156
+ app,
157
+ tableKey: opts.tableKey,
158
+ clientFactory: opts.clientFactory
159
+ });
160
+ const systemPresetsResolved = computed(() => resolveSystemPresets(opts.systemPresets));
161
+ const presets = shallowRef([]);
162
+ const userConf = shallowRef(null);
163
+ const capabilities = ref(null);
164
+ const loading = ref(false);
165
+ const error = ref(null);
166
+ const denied = ref(false);
167
+ const activePresetId = ref(null);
168
+ const available = computed(() => !denied.value);
169
+ const presetsById = computed(() => {
170
+ const map = /* @__PURE__ */ new Map();
171
+ for (const row of presets.value) map.set(row.id, row);
172
+ return map;
173
+ });
174
+ const systemPresetsById = computed(() => {
175
+ const map = /* @__PURE__ */ new Map();
176
+ for (const sp of systemPresetsResolved.value) map.set(sp.id, sp);
177
+ return map;
178
+ });
179
+ const activePreset = computed(() => {
180
+ const id = activePresetId.value;
181
+ if (!id) return null;
182
+ if (isSystemPresetId(id)) {
183
+ const entry = systemPresetsById.value.get(id);
184
+ return entry ? {
185
+ kind: "system",
186
+ entry
187
+ } : null;
188
+ }
189
+ const entry = presetsById.value.get(id);
190
+ return entry ? {
191
+ kind: "stored",
192
+ entry
193
+ } : null;
194
+ });
195
+ const currentUser = computed(() => {
196
+ const fromCaps = capabilities.value?.userId;
197
+ if (typeof fromCaps === "string" && fromCaps.length > 0) return fromCaps;
198
+ for (const row of presets.value) if (row.public !== true && typeof row.user === "string" && row.user.length > 0) return row.user;
199
+ return null;
200
+ });
201
+ function isOwned(id) {
202
+ if (isSystemPresetId(id)) return false;
203
+ const row = presetsById.value.get(id);
204
+ if (!row) return false;
205
+ if (row.public !== true) return true;
206
+ const me = currentUser.value;
207
+ return me !== null && row.user === me;
208
+ }
209
+ /**
210
+ * @param opts.capabilities — set `false` for refresh-after-mutation calls
211
+ * (fav-toggle, save, rename, delete, public-toggle, set-default) where
212
+ * role-derived capabilities can't have changed. Default `true`, used
213
+ * only on the initial mount load.
214
+ */
215
+ let batchDepth = 0;
216
+ let reloadPending = false;
217
+ async function maybeReloadAfterMutation() {
218
+ if (batchDepth > 0) {
219
+ reloadPending = true;
220
+ return;
221
+ }
222
+ await reload({ capabilities: false });
223
+ }
224
+ async function batch(fn) {
225
+ batchDepth++;
226
+ try {
227
+ return await fn();
228
+ } finally {
229
+ batchDepth--;
230
+ if (batchDepth === 0 && reloadPending) {
231
+ reloadPending = false;
232
+ await reload({ capabilities: false });
233
+ }
234
+ }
235
+ }
236
+ async function reload(opts = {}) {
237
+ loading.value = true;
238
+ error.value = null;
239
+ try {
240
+ const result = await client.list(opts);
241
+ if (result.denied) {
242
+ denied.value = true;
243
+ presets.value = [];
244
+ userConf.value = null;
245
+ capabilities.value = null;
246
+ return;
247
+ }
248
+ denied.value = false;
249
+ presets.value = result.presets;
250
+ userConf.value = result.userConf;
251
+ if (result.capabilities !== void 0) capabilities.value = result.capabilities;
252
+ } catch (err) {
253
+ if (isAuthError(err)) {
254
+ denied.value = true;
255
+ presets.value = [];
256
+ userConf.value = null;
257
+ capabilities.value = null;
258
+ return;
259
+ }
260
+ error.value = err;
261
+ console.warn("[vue-table] usePresets load failed:", err);
262
+ } finally {
263
+ loading.value = false;
264
+ }
265
+ }
266
+ async function savePreset(snapshot) {
267
+ const id = activePresetId.value;
268
+ if (!id) throw new Error("[vue-table] usePresets.savePreset: no active preset");
269
+ if (isSystemPresetId(id)) throw new Error("[vue-table] usePresets.savePreset: system presets cannot be overwritten");
270
+ const row = presetsById.value.get(id);
271
+ const label = row?.label ?? (row?.data)?.label ?? "";
272
+ if (!label) throw new Error("[vue-table] usePresets.savePreset: existing preset has no label");
273
+ await client.savePreset(id, label, snapshot);
274
+ await maybeReloadAfterMutation();
275
+ }
276
+ async function savePresetAs(label, snapshot, saveOpts = {}) {
277
+ const result = await client.savePresetAs(label, snapshot, saveOpts);
278
+ await maybeReloadAfterMutation();
279
+ activePresetId.value = result.id;
280
+ return result.id;
281
+ }
282
+ async function renamePreset(id, label) {
283
+ if (isSystemPresetId(id)) throw new Error("[vue-table] usePresets.renamePreset: system presets cannot be renamed");
284
+ await client.renamePreset(id, label);
285
+ await maybeReloadAfterMutation();
286
+ }
287
+ async function deletePreset(id) {
288
+ if (isSystemPresetId(id)) throw new Error("[vue-table] usePresets.deletePreset: system presets cannot be deleted");
289
+ await client.deletePreset(id);
290
+ if (activePresetId.value === id) activePresetId.value = STANDARD_PRESET_ID;
291
+ await maybeReloadAfterMutation();
292
+ }
293
+ async function togglePublic(id) {
294
+ if (isSystemPresetId(id)) throw new Error("[vue-table] usePresets.togglePublic: system presets are not public");
295
+ const row = presetsById.value.get(id);
296
+ if (!row) return;
297
+ await client.setPublic(id, row.public !== true);
298
+ await maybeReloadAfterMutation();
299
+ }
300
+ async function setDefault(id) {
301
+ const user = currentUser.value ?? void 0;
302
+ await client.upsertUserConf(userConf.value, { defaultPresetId: id ?? void 0 }, user);
303
+ await maybeReloadAfterMutation();
304
+ }
305
+ async function toggleFav(id) {
306
+ const current = (userConf.value?.data)?.favPresetIds;
307
+ const set = new Set(current ?? []);
308
+ if (set.has(id)) set.delete(id);
309
+ else set.add(id);
310
+ await setFavorites([...set]);
311
+ }
312
+ async function setFavorites(ids) {
313
+ const user = currentUser.value ?? void 0;
314
+ await client.upsertUserConf(userConf.value, { favPresetIds: ids }, user);
315
+ if (userConf.value) userConf.value = {
316
+ ...userConf.value,
317
+ data: {
318
+ ...userConf.value.data,
319
+ favPresetIds: ids
320
+ }
321
+ };
322
+ await maybeReloadAfterMutation();
323
+ }
324
+ if (opts.autoLoad !== false) reload();
325
+ return {
326
+ presets,
327
+ presetsById,
328
+ userConf,
329
+ capabilities,
330
+ systemPresets: systemPresetsResolved,
331
+ systemPresetsById,
332
+ available,
333
+ loading,
334
+ error,
335
+ currentUser,
336
+ activePresetId,
337
+ activePreset,
338
+ isOwned,
339
+ reload,
340
+ batch,
341
+ savePreset,
342
+ savePresetAs,
343
+ renamePreset,
344
+ deletePreset,
345
+ togglePublic,
346
+ setDefault,
347
+ toggleFav,
348
+ setFavorites
349
+ };
350
+ }
351
+ //#endregion
352
+ //#region src/composables/use-table.ts
353
+ /** Thin alias over `resetMetaCache` — retained so existing test code keeps working. */
354
+ function clearTableCache() {
355
+ resetMetaCache();
356
+ }
357
+ /**
358
+ * Main entry composable for table setup.
359
+ *
360
+ * @param url — Table endpoint URL (e.g. "/db/tables/products")
361
+ */
362
+ function useTable(url, opts) {
363
+ const entry = getMetaEntry(url, opts?.clientFactory);
364
+ if (!entry.tableDef) entry.tableDef = Promise.all([entry.meta, entry.type]).then(([meta, type]) => createTableDef(meta, type));
365
+ const { client } = entry;
366
+ const defPromise = entry.tableDef;
367
+ const preset = opts?.preset;
368
+ const presetsHandle = preset ? usePresets({
369
+ url: preset.url,
370
+ tableKey: preset.tableKey,
371
+ app: preset.app,
372
+ clientFactory: opts?.clientFactory,
373
+ systemPresets: preset.systemPresets
374
+ }) : null;
375
+ const draftHandle = preset ? useLocalDraft({
376
+ app: injectPresetsApp(preset.app),
377
+ tableKey: preset.tableKey,
378
+ enabled: preset.persistDrafts ?? false,
379
+ availableAspects: preset.aspects ?? DEFAULT_AVAILABLE_ASPECTS
380
+ }) : null;
381
+ const { state, internals } = createTableState({
382
+ client,
383
+ limit: opts?.limit,
384
+ selection: {
385
+ rowValueFn: opts?.rowValueFn,
386
+ selectedRows: opts?.selectedRows
387
+ },
388
+ model: {
389
+ filterFields: opts?.filterFields,
390
+ columnNames: opts?.columnNames,
391
+ columnWidths: opts?.columnWidths,
392
+ sorters: opts?.sorters
393
+ },
394
+ query: {
395
+ fn: opts?.queryFn,
396
+ forceFilters: opts?.forceFilters,
397
+ forceSorters: opts?.forceSorters,
398
+ alwaysSelected: opts?.alwaysSelected,
399
+ blockQuery: opts?.blockQuery,
400
+ queryOnMount: opts?.queryOnMount,
401
+ urlQueryReady: opts?.urlQueryReady,
402
+ onUrlQueryChange: opts?.onUrlQueryChange,
403
+ urlQuerySync: opts?.urlQuerySync
404
+ },
405
+ window: {
406
+ blockSize: opts?.blockSize,
407
+ dragReleaseDebounceMs: opts?.dragReleaseDebounceMs
408
+ },
409
+ actions: {
410
+ refreshOnAction: opts?.refreshOnAction,
411
+ onResolved: opts?.onActionResolved
412
+ },
413
+ preset: {
414
+ presetsHandle,
415
+ draftHandle,
416
+ availableAspects: preset?.aspects,
417
+ persistDrafts: preset?.persistDrafts ?? false
418
+ }
419
+ });
420
+ useTableSelection(state, { mode: opts?.selectionPersistence ?? "trim" });
421
+ if (opts?.provideContext !== false) provideTableContext({
422
+ state,
423
+ client,
424
+ controls: opts?.controls ?? {},
425
+ types: opts?.types,
426
+ components: opts?.components,
427
+ formTypes: opts?.formTypes,
428
+ formComponents: opts?.formComponents
429
+ });
430
+ defPromise.then((def) => {
431
+ internals.init(def);
432
+ }).catch((err) => {
433
+ state.metadataError.value = err instanceof Error ? err : new Error(String(err));
434
+ }).finally(() => {
435
+ state.loadingMetadata.value = false;
436
+ });
437
+ return state;
438
+ }
439
+ //#endregion
440
+ export { AS_PRESETS_APP as a, useLocalDraft as i, useTable as n, injectPresetsApp as o, usePresets as r, clearTableCache as t };
@@ -1,17 +1,4 @@
1
- let vue = require("vue");
2
1
  let _atscript_ui_table = require("@atscript/ui-table");
3
- //#region src/composables/use-has-emit-listener.ts
4
- /**
5
- * Returns true when the parent component bound a v-on listener for `emitName`
6
- * (e.g. `onMainAction` for `@main-action`). Reads `inst.vnode.props` — the
7
- * same property Vue uses to dispatch emit listeners. Non-reactive: a parent
8
- * remount via `v-if` re-evaluates at the new mount.
9
- */
10
- function useHasEmitListener(emitName) {
11
- const inst = (0, vue.getCurrentInstance)();
12
- return (0, vue.computed)(() => !!inst?.vnode.props?.[emitName]);
13
- }
14
- //#endregion
15
2
  //#region src/composables/use-table-column-handlers.ts
16
3
  /**
17
4
  * Pure pass-through handlers shared between the pagination renderer
@@ -51,12 +38,6 @@ function useTableColumnHandlers(state) {
51
38
  };
52
39
  }
53
40
  //#endregion
54
- Object.defineProperty(exports, "useHasEmitListener", {
55
- enumerable: true,
56
- get: function() {
57
- return useHasEmitListener;
58
- }
59
- });
60
41
  Object.defineProperty(exports, "useTableColumnHandlers", {
61
42
  enumerable: true,
62
43
  get: function() {
@@ -1,17 +1,4 @@
1
- import { computed, getCurrentInstance } from "vue";
2
1
  import { reorderColumnNames } from "@atscript/ui-table";
3
- //#region src/composables/use-has-emit-listener.ts
4
- /**
5
- * Returns true when the parent component bound a v-on listener for `emitName`
6
- * (e.g. `onMainAction` for `@main-action`). Reads `inst.vnode.props` — the
7
- * same property Vue uses to dispatch emit listeners. Non-reactive: a parent
8
- * remount via `v-if` re-evaluates at the new mount.
9
- */
10
- function useHasEmitListener(emitName) {
11
- const inst = getCurrentInstance();
12
- return computed(() => !!inst?.vnode.props?.[emitName]);
13
- }
14
- //#endregion
15
2
  //#region src/composables/use-table-column-handlers.ts
16
3
  /**
17
4
  * Pure pass-through handlers shared between the pagination renderer
@@ -51,4 +38,4 @@ function useTableColumnHandlers(state) {
51
38
  };
52
39
  }
53
40
  //#endregion
54
- export { useHasEmitListener as n, useTableColumnHandlers as t };
41
+ export { useTableColumnHandlers as t };
@@ -0,0 +1,12 @@
1
+ import { o as useTableContextOptional } from "./use-table-state-CuZ2OXoY.mjs";
2
+ //#region src/composables/use-table-component.ts
3
+ /**
4
+ * Resolve a single skin-slot component from the injected `controls` map,
5
+ * falling back to the default. Safe to call outside a table context (e.g.
6
+ * a default mounted standalone in tests) — the fallback is returned.
7
+ */
8
+ function useTableComponent(key, fallback) {
9
+ return useTableContextOptional()?.controls[key] ?? fallback;
10
+ }
11
+ //#endregion
12
+ export { useTableComponent as t };
@@ -0,0 +1,17 @@
1
+ const require_use_table_state = require("./use-table-state-DFQ30m-j.cjs");
2
+ //#region src/composables/use-table-component.ts
3
+ /**
4
+ * Resolve a single skin-slot component from the injected `controls` map,
5
+ * falling back to the default. Safe to call outside a table context (e.g.
6
+ * a default mounted standalone in tests) — the fallback is returned.
7
+ */
8
+ function useTableComponent(key, fallback) {
9
+ return require_use_table_state.useTableContextOptional()?.controls[key] ?? fallback;
10
+ }
11
+ //#endregion
12
+ Object.defineProperty(exports, "useTableComponent", {
13
+ enumerable: true,
14
+ get: function() {
15
+ return useTableComponent;
16
+ }
17
+ });
@@ -0,0 +1,57 @@
1
+ const require_use_table_state = require("./use-table-state-DFQ30m-j.cjs");
2
+ //#region src/composables/use-table-nav-bridge.ts
3
+ function isPassthroughKey(event) {
4
+ const key = event.key;
5
+ const meta = event.metaKey;
6
+ const ctrl = event.ctrlKey;
7
+ const alt = event.altKey;
8
+ if (key === " ") return true;
9
+ if (key.length === 1 && !meta && !ctrl && !alt) return true;
10
+ if ((key === "Home" || key === "End") && !meta && !ctrl && !alt) return true;
11
+ return false;
12
+ }
13
+ /**
14
+ * Construct a keyboard-bridge for an external `<input>` to drive table nav
15
+ * without losing focus. Without args, injects the nearest `<as-table-root>`
16
+ * context's state. With an explicit `state`, binds to that state. With
17
+ * `opts.enterAction`, the returned bridge's `onKeydown` defaults to that
18
+ * enter-action (per-call options still win).
19
+ *
20
+ * Each call returns a fresh bridge object — callers that need stable
21
+ * identity should bind once at setup and reuse the binding.
22
+ */
23
+ function useTableNavBridge(state, opts) {
24
+ let target = state;
25
+ if (!target) {
26
+ const ctx = require_use_table_state.useTableContextOptional();
27
+ if (!ctx) throw new Error("[vue-table] useTableNavBridge() called outside of <as-table-root>.");
28
+ target = ctx.state;
29
+ }
30
+ const bound = target;
31
+ const defaultEnterAction = opts?.enterAction;
32
+ const modeOpt = opts?.mode;
33
+ const readMode = () => {
34
+ if (typeof modeOpt === "function") return modeOpt();
35
+ return modeOpt ?? "none";
36
+ };
37
+ function onKeydown(event, callOpts) {
38
+ if (isPassthroughKey(event)) return;
39
+ bound.handleNavKey(event, {
40
+ enterAction: callOpts?.enterAction ?? defaultEnterAction,
41
+ mode: callOpts?.mode ?? readMode()
42
+ });
43
+ }
44
+ return {
45
+ onKeydown,
46
+ activeIndex: bound.activeIndex,
47
+ setActive: bound.setActive,
48
+ clearActive: bound.clearActive
49
+ };
50
+ }
51
+ //#endregion
52
+ Object.defineProperty(exports, "useTableNavBridge", {
53
+ enumerable: true,
54
+ get: function() {
55
+ return useTableNavBridge;
56
+ }
57
+ });
@@ -0,0 +1,52 @@
1
+ import { o as useTableContextOptional } from "./use-table-state-CuZ2OXoY.mjs";
2
+ //#region src/composables/use-table-nav-bridge.ts
3
+ function isPassthroughKey(event) {
4
+ const key = event.key;
5
+ const meta = event.metaKey;
6
+ const ctrl = event.ctrlKey;
7
+ const alt = event.altKey;
8
+ if (key === " ") return true;
9
+ if (key.length === 1 && !meta && !ctrl && !alt) return true;
10
+ if ((key === "Home" || key === "End") && !meta && !ctrl && !alt) return true;
11
+ return false;
12
+ }
13
+ /**
14
+ * Construct a keyboard-bridge for an external `<input>` to drive table nav
15
+ * without losing focus. Without args, injects the nearest `<as-table-root>`
16
+ * context's state. With an explicit `state`, binds to that state. With
17
+ * `opts.enterAction`, the returned bridge's `onKeydown` defaults to that
18
+ * enter-action (per-call options still win).
19
+ *
20
+ * Each call returns a fresh bridge object — callers that need stable
21
+ * identity should bind once at setup and reuse the binding.
22
+ */
23
+ function useTableNavBridge(state, opts) {
24
+ let target = state;
25
+ if (!target) {
26
+ const ctx = useTableContextOptional();
27
+ if (!ctx) throw new Error("[vue-table] useTableNavBridge() called outside of <as-table-root>.");
28
+ target = ctx.state;
29
+ }
30
+ const bound = target;
31
+ const defaultEnterAction = opts?.enterAction;
32
+ const modeOpt = opts?.mode;
33
+ const readMode = () => {
34
+ if (typeof modeOpt === "function") return modeOpt();
35
+ return modeOpt ?? "none";
36
+ };
37
+ function onKeydown(event, callOpts) {
38
+ if (isPassthroughKey(event)) return;
39
+ bound.handleNavKey(event, {
40
+ enterAction: callOpts?.enterAction ?? defaultEnterAction,
41
+ mode: callOpts?.mode ?? readMode()
42
+ });
43
+ }
44
+ return {
45
+ onKeydown,
46
+ activeIndex: bound.activeIndex,
47
+ setActive: bound.setActive,
48
+ clearActive: bound.clearActive
49
+ };
50
+ }
51
+ //#endregion
52
+ export { useTableNavBridge as t };
@@ -0,0 +1,59 @@
1
+ import { watch } from "vue";
2
+ import { trimSelection } from "@atscript/ui-table";
3
+ //#region src/composables/use-table-selection.ts
4
+ /**
5
+ * Renderer-owned cleanup for the `select` prop transition. Dropping into
6
+ * `'none'` clears `selectedRows` so the next opt-in to multi-mode starts
7
+ * clean; other transitions are no-ops (`'none' → 'multi'` already has an
8
+ * empty selection, `'multi' → 'multi'` doesn't change semantics). The
9
+ * getter is invoked once per change — NOT immediate, so the mount-time
10
+ * default `'none'` doesn't clobber externally-seeded selections.
11
+ *
12
+ * Lives outside `useTableSelection` because selection mode is a renderer
13
+ * concern (a prop, not state) — both `<AsTable>` and `<AsWindowTable>`
14
+ * call this from their setup so the cleanup tracks the renderer's prop.
15
+ */
16
+ function useSelectModeReset(state, selectGetter) {
17
+ watch(selectGetter, (next, prev) => {
18
+ if (next === "none" && prev !== "none" && state.selectedRows.value.length > 0) state.selectedRows.value = [];
19
+ });
20
+ }
21
+ /**
22
+ * Wire up selection reconciliation on results change.
23
+ *
24
+ * The watcher distinguishes results-replacement (query / invalidate /
25
+ * pagination jump) from results-extension in EITHER direction (queryNext /
26
+ * forward-merging loadRange / backward-merging loadRange) and only runs the
27
+ * reconciliation logic on replacement. Backward extension prepends rows AND
28
+ * decrements `resultsStart` — caught via the last-row reference identity
29
+ * check, so scrolling upward doesn't silently mutate selection.
30
+ *
31
+ * Mode semantics on results-replacement:
32
+ * - `"persist"` — no-op; the consumer's ref is untouched.
33
+ * - `"trim"` (default) — keep the subset of selected PKs still present in the new results.
34
+ * - `"clear"` — drop everything.
35
+ */
36
+ function useTableSelection(state, opts) {
37
+ const mode = opts?.mode ?? "trim";
38
+ watch([() => state.results.value, () => state.resultsStart.value], ([newResults, newResultsStart], [oldResults, oldResultsStart]) => {
39
+ if (mode === "persist") return;
40
+ if (state.selectedRows.value.length === 0) return;
41
+ const oldArr = oldResults ?? [];
42
+ const newArr = newResults;
43
+ const oldStart = oldResultsStart ?? 0;
44
+ const delta = newArr.length - oldArr.length;
45
+ if (delta > 0 && oldArr.length > 0) {
46
+ if (newResultsStart === oldStart && newArr[0] === oldArr[0]) return;
47
+ if (newResultsStart === oldStart - delta && newArr[newArr.length - 1] === oldArr[oldArr.length - 1]) return;
48
+ }
49
+ if (mode === "clear") {
50
+ state.selectedRows.value = [];
51
+ return;
52
+ }
53
+ const presentPks = /* @__PURE__ */ new Set();
54
+ for (const r of newArr) presentPks.add(state.rowValueFn(r));
55
+ state.selectedRows.value = trimSelection(state.selectedRows.value, presentPks);
56
+ });
57
+ }
58
+ //#endregion
59
+ export { useTableSelection as n, useSelectModeReset as t };