@atscript/vue-table 0.1.58

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 (202) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +24 -0
  3. package/dist/as-action-form-dialog.cjs +221 -0
  4. package/dist/as-action-form-dialog.d.cts +6 -0
  5. package/dist/as-action-form-dialog.d.mts +7 -0
  6. package/dist/as-action-form-dialog.mjs +221 -0
  7. package/dist/as-action-menu-content-CXsdPn42.mjs +104 -0
  8. package/dist/as-action-menu-content-CyUfBrWH.cjs +109 -0
  9. package/dist/as-cell-array-CXeZzZqt.cjs +69 -0
  10. package/dist/as-cell-array-DOQKR6t5.mjs +64 -0
  11. package/dist/as-cell-array.cjs +3 -0
  12. package/dist/as-cell-array.d.cts +2 -0
  13. package/dist/as-cell-array.d.mts +2 -0
  14. package/dist/as-cell-array.mjs +3 -0
  15. package/dist/as-cell-array.vue-DZGM2VHh.d.mts +12 -0
  16. package/dist/as-cell-array.vue-pFs5GcCR.d.cts +12 -0
  17. package/dist/as-cell-date-CTrvxS1h.cjs +78 -0
  18. package/dist/as-cell-date-Cq49RHmL.mjs +73 -0
  19. package/dist/as-cell-date.cjs +3 -0
  20. package/dist/as-cell-date.d.cts +2 -0
  21. package/dist/as-cell-date.d.mts +2 -0
  22. package/dist/as-cell-date.mjs +3 -0
  23. package/dist/as-cell-date.vue-BBSps2B2.d.cts +12 -0
  24. package/dist/as-cell-date.vue-Zlt4mHWb.d.mts +12 -0
  25. package/dist/as-cell-json-BynWIs1d.mjs +37 -0
  26. package/dist/as-cell-json-DvHvQ6IL.cjs +42 -0
  27. package/dist/as-cell-json-popover-BWdNs1YU.cjs +70 -0
  28. package/dist/as-cell-json-popover-DUq25I0L.mjs +65 -0
  29. package/dist/as-cell-json.cjs +3 -0
  30. package/dist/as-cell-json.d.cts +2 -0
  31. package/dist/as-cell-json.d.mts +2 -0
  32. package/dist/as-cell-json.mjs +3 -0
  33. package/dist/as-cell-json.vue-C6wg4ARZ.d.cts +12 -0
  34. package/dist/as-cell-json.vue-CESWuCer.d.mts +12 -0
  35. package/dist/as-cell-number-0_WrSCzu.cjs +76 -0
  36. package/dist/as-cell-number-Bc1C97Vg.mjs +71 -0
  37. package/dist/as-cell-number.cjs +3 -0
  38. package/dist/as-cell-number.d.cts +2 -0
  39. package/dist/as-cell-number.d.mts +2 -0
  40. package/dist/as-cell-number.mjs +3 -0
  41. package/dist/as-cell-number.vue-1Oq7nVI3.d.mts +12 -0
  42. package/dist/as-cell-number.vue-CJ2K5zeM.d.cts +12 -0
  43. package/dist/as-cell-union-C1w3B38J.mjs +88 -0
  44. package/dist/as-cell-union-CFAI0utz.cjs +93 -0
  45. package/dist/as-cell-union.cjs +4 -0
  46. package/dist/as-cell-union.d.cts +2 -0
  47. package/dist/as-cell-union.d.mts +2 -0
  48. package/dist/as-cell-union.mjs +4 -0
  49. package/dist/as-cell-union.vue-CslPM_c2.d.cts +12 -0
  50. package/dist/as-cell-union.vue-NnDmQZOA.d.mts +12 -0
  51. package/dist/as-column-menu-CH9Htz0Q.cjs +220 -0
  52. package/dist/as-column-menu-DCfhorMP.mjs +215 -0
  53. package/dist/as-column-menu.cjs +2 -0
  54. package/dist/as-column-menu.d.cts +2 -0
  55. package/dist/as-column-menu.d.mts +2 -0
  56. package/dist/as-column-menu.mjs +2 -0
  57. package/dist/as-column-menu.vue-C9e6wJ3z.d.mts +47 -0
  58. package/dist/as-column-menu.vue-o0qFdzoL.d.cts +47 -0
  59. package/dist/as-config-dialog-d2k7_l0U.cjs +699 -0
  60. package/dist/as-config-dialog-vRklaKbi.mjs +688 -0
  61. package/dist/as-config-dialog.cjs +3 -0
  62. package/dist/as-config-dialog.d.cts +2 -0
  63. package/dist/as-config-dialog.d.mts +2 -0
  64. package/dist/as-config-dialog.mjs +3 -0
  65. package/dist/as-config-dialog.vue-C6Q62xF5.d.mts +7 -0
  66. package/dist/as-config-dialog.vue-DvvJi3xx.d.cts +7 -0
  67. package/dist/as-confirm-dialog-BLh3Ju4-.mjs +52 -0
  68. package/dist/as-confirm-dialog-BgpIEE2z.cjs +57 -0
  69. package/dist/as-confirm-dialog.cjs +3 -0
  70. package/dist/as-confirm-dialog.d.cts +2 -0
  71. package/dist/as-confirm-dialog.d.mts +2 -0
  72. package/dist/as-confirm-dialog.mjs +3 -0
  73. package/dist/as-confirm-dialog.vue-CXxLpzbu.d.cts +7 -0
  74. package/dist/as-confirm-dialog.vue-pas8jGhv.d.mts +7 -0
  75. package/dist/as-filter-dialog-C0HMpUPT.mjs +610 -0
  76. package/dist/as-filter-dialog-DcGvIV3h.cjs +621 -0
  77. package/dist/as-filter-dialog.cjs +15 -0
  78. package/dist/as-filter-dialog.d.cts +2 -0
  79. package/dist/as-filter-dialog.d.mts +2 -0
  80. package/dist/as-filter-dialog.mjs +15 -0
  81. package/dist/as-filter-dialog.vue-BV2J8PgZ.d.cts +7 -0
  82. package/dist/as-filter-dialog.vue-RDZjp4gJ.d.mts +7 -0
  83. package/dist/as-filter-field-B_tYzvvl.cjs +984 -0
  84. package/dist/as-filter-field-Bqvu2ASN.mjs +943 -0
  85. package/dist/as-filter-field.cjs +9 -0
  86. package/dist/as-filter-field.d.cts +2 -0
  87. package/dist/as-filter-field.d.mts +2 -0
  88. package/dist/as-filter-field.mjs +9 -0
  89. package/dist/as-filter-field.vue-ByQ8xIGq.d.cts +11 -0
  90. package/dist/as-filter-field.vue-QY8wi5S5.d.mts +11 -0
  91. package/dist/as-filter-input--nr72iwX.cjs +106 -0
  92. package/dist/as-filter-input-P1i0CW2-.mjs +101 -0
  93. package/dist/as-filter-input.cjs +2 -0
  94. package/dist/as-filter-input.d.cts +2 -0
  95. package/dist/as-filter-input.d.mts +2 -0
  96. package/dist/as-filter-input.mjs +2 -0
  97. package/dist/as-filter-input.vue-CBQ71eNg.d.mts +18 -0
  98. package/dist/as-filter-input.vue-CS4nOk_Q.d.cts +18 -0
  99. package/dist/as-filters-Bxa9ZEMm.mjs +44 -0
  100. package/dist/as-filters-xRT2qv56.cjs +49 -0
  101. package/dist/as-filters.cjs +10 -0
  102. package/dist/as-filters.d.cts +2 -0
  103. package/dist/as-filters.d.mts +2 -0
  104. package/dist/as-filters.mjs +10 -0
  105. package/dist/as-filters.vue-BsMgYUcX.d.mts +10 -0
  106. package/dist/as-filters.vue-fv-tRL2H.d.cts +10 -0
  107. package/dist/as-preset-dialog-BaTfwMnh.cjs +569 -0
  108. package/dist/as-preset-dialog-BdDRgwf_.mjs +564 -0
  109. package/dist/as-preset-dialog.cjs +4 -0
  110. package/dist/as-preset-dialog.d.cts +2 -0
  111. package/dist/as-preset-dialog.d.mts +2 -0
  112. package/dist/as-preset-dialog.mjs +4 -0
  113. package/dist/as-preset-dialog.vue-Bzv-ON9W.d.mts +7 -0
  114. package/dist/as-preset-dialog.vue-DP9fy00Y.d.cts +7 -0
  115. package/dist/as-preset-picker-BQbNEiy9.mjs +427 -0
  116. package/dist/as-preset-picker-Ce3crTQy.cjs +432 -0
  117. package/dist/as-preset-picker.cjs +4 -0
  118. package/dist/as-preset-picker.d.cts +2 -0
  119. package/dist/as-preset-picker.d.mts +2 -0
  120. package/dist/as-preset-picker.mjs +4 -0
  121. package/dist/as-preset-picker.vue-CTBk6leV.d.mts +7 -0
  122. package/dist/as-preset-picker.vue-DfXS3pGl.d.cts +7 -0
  123. package/dist/as-row-actions-B6Kob6gt.cjs +120 -0
  124. package/dist/as-row-actions-CeWBBGqh.mjs +115 -0
  125. package/dist/as-row-actions.cjs +4 -0
  126. package/dist/as-row-actions.d.cts +2 -0
  127. package/dist/as-row-actions.d.mts +2 -0
  128. package/dist/as-row-actions.mjs +4 -0
  129. package/dist/as-row-actions.vue-BPaQfGev.d.mts +11 -0
  130. package/dist/as-row-actions.vue-Bvcc2tUN.d.cts +11 -0
  131. package/dist/as-table-Cnw2fOqZ.mjs +204 -0
  132. package/dist/as-table-DlDFxdXI.cjs +209 -0
  133. package/dist/as-table-actions-BK1Thy2G.cjs +142 -0
  134. package/dist/as-table-actions-BpMiNFni.mjs +137 -0
  135. package/dist/as-table-actions.cjs +4 -0
  136. package/dist/as-table-actions.d.cts +2 -0
  137. package/dist/as-table-actions.d.mts +2 -0
  138. package/dist/as-table-actions.mjs +4 -0
  139. package/dist/as-table-actions.vue-B7Q-JA3z.d.cts +47 -0
  140. package/dist/as-table-actions.vue-Bs1Jl1ep.d.mts +47 -0
  141. package/dist/as-table-base-D0k4k7k_.mjs +646 -0
  142. package/dist/as-table-base-VIz-B_6_.cjs +651 -0
  143. package/dist/as-table-cell-value-B1CiJYFn.mjs +26 -0
  144. package/dist/as-table-cell-value-CuxRtFn9.cjs +31 -0
  145. package/dist/as-table-cell-value.cjs +3 -0
  146. package/dist/as-table-cell-value.d.cts +2 -0
  147. package/dist/as-table-cell-value.d.mts +2 -0
  148. package/dist/as-table-cell-value.mjs +3 -0
  149. package/dist/as-table-cell-value.vue-BgFDv2JQ.d.cts +12 -0
  150. package/dist/as-table-cell-value.vue-BuPCQ8YA.d.mts +12 -0
  151. package/dist/as-table-header-cell-C3zeZUZo.cjs +117 -0
  152. package/dist/as-table-header-cell-CBn_ioCe.mjs +112 -0
  153. package/dist/as-table-header-cell.cjs +3 -0
  154. package/dist/as-table-header-cell.d.cts +2 -0
  155. package/dist/as-table-header-cell.d.mts +2 -0
  156. package/dist/as-table-header-cell.mjs +3 -0
  157. package/dist/as-table-header-cell.vue-Bc_DSsGY.d.cts +31 -0
  158. package/dist/as-table-header-cell.vue-DNMOHfek.d.mts +31 -0
  159. package/dist/as-table-root-Br6WcGRo.cjs +263 -0
  160. package/dist/as-table-root-gG7pTIdD.mjs +258 -0
  161. package/dist/as-table-root.cjs +28 -0
  162. package/dist/as-table-root.d.cts +2 -0
  163. package/dist/as-table-root.d.mts +2 -0
  164. package/dist/as-table-root.mjs +28 -0
  165. package/dist/as-table-root.vue-5_OhVwse.d.mts +2258 -0
  166. package/dist/as-table-root.vue-CSqEtIll.d.cts +2258 -0
  167. package/dist/as-table-status-BjRGGuhC.mjs +683 -0
  168. package/dist/as-table-status-DWYoJIMC.cjs +724 -0
  169. package/dist/as-table.cjs +10 -0
  170. package/dist/as-table.d.cts +2 -0
  171. package/dist/as-table.d.mts +2 -0
  172. package/dist/as-table.mjs +10 -0
  173. package/dist/as-table.vue-BTYg-e3Z.d.mts +81 -0
  174. package/dist/as-table.vue-wdRARLIe.d.cts +81 -0
  175. package/dist/as-window-table-CKIfo3M_.mjs +709 -0
  176. package/dist/as-window-table-DE7_NyEP.cjs +714 -0
  177. package/dist/as-window-table.cjs +9 -0
  178. package/dist/as-window-table.d.cts +2 -0
  179. package/dist/as-window-table.d.mts +2 -0
  180. package/dist/as-window-table.mjs +9 -0
  181. package/dist/as-window-table.vue-Bf8xGC9M.d.mts +86 -0
  182. package/dist/as-window-table.vue-CA8qsrz4.d.cts +86 -0
  183. package/dist/format-cell-B2xMDYO9.mjs +27 -0
  184. package/dist/format-cell-D4mqaN0E.cjs +32 -0
  185. package/dist/get-cell-value-CZSVfDLg.cjs +19 -0
  186. package/dist/get-cell-value-DiH84HKL.mjs +14 -0
  187. package/dist/index.cjs +598 -0
  188. package/dist/index.d.cts +21 -0
  189. package/dist/index.d.mts +21 -0
  190. package/dist/index.mjs +505 -0
  191. package/dist/preset-aspect-display-BYeiSgcc.mjs +43 -0
  192. package/dist/preset-aspect-display-y8aal_EF.cjs +72 -0
  193. package/dist/types-BvvXN72P.d.mts +531 -0
  194. package/dist/types-CNMmF6W2.d.cts +531 -0
  195. package/dist/use-cell-locale-1uQaFTLQ.mjs +23 -0
  196. package/dist/use-cell-locale-B480_QYK.cjs +34 -0
  197. package/dist/use-table-column-handlers-CGYAY2xH.cjs +65 -0
  198. package/dist/use-table-column-handlers-t6xi1yCE.mjs +54 -0
  199. package/dist/use-table-state-C4JbonEZ.mjs +1822 -0
  200. package/dist/use-table-state-MU-vuzui.cjs +1917 -0
  201. package/package.json +195 -0
  202. package/styles.d.ts +2 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,505 @@
1
+ import { a as useTableContext, d as extractIdentifier, g as ROW_ACTIONS_TYPE, n as createTableState, o as useTableContextOptional, t as createStaticTableState } from "./use-table-state-C4JbonEZ.mjs";
2
+ import { s as useTableSelection } from "./as-table-status-BjRGGuhC.mjs";
3
+ import { a as useLocalDraft, i as usePresets, n as clearTableCache, o as AS_PRESETS_APP, r as useTable, s as injectPresetsApp, t as as_filter_field_default } from "./as-filter-field-Bqvu2ASN.mjs";
4
+ import { n as useTableNavBridge, t as as_filter_dialog_default } from "./as-filter-dialog-C0HMpUPT.mjs";
5
+ import "./use-table-column-handlers-t6xi1yCE.mjs";
6
+ import { t as getCellValue } from "./get-cell-value-DiH84HKL.mjs";
7
+ import "./as-cell-json-popover-DUq25I0L.mjs";
8
+ import { t as as_cell_array_default } from "./as-cell-array-DOQKR6t5.mjs";
9
+ import { t as as_cell_date_default } from "./as-cell-date-Cq49RHmL.mjs";
10
+ import { n as useCellLocale, t as provideCellLocale } from "./use-cell-locale-1uQaFTLQ.mjs";
11
+ import { t as as_cell_json_default } from "./as-cell-json-BynWIs1d.mjs";
12
+ import { t as as_cell_number_default } from "./as-cell-number-Bc1C97Vg.mjs";
13
+ import { t as formatCellValue } from "./format-cell-B2xMDYO9.mjs";
14
+ import { t as as_cell_union_default } from "./as-cell-union-C1w3B38J.mjs";
15
+ import { t as as_column_menu_default } from "./as-column-menu-DCfhorMP.mjs";
16
+ import { t as as_config_dialog_default } from "./as-config-dialog-vRklaKbi.mjs";
17
+ import { t as as_confirm_dialog_default } from "./as-confirm-dialog-BLh3Ju4-.mjs";
18
+ import { t as as_filter_input_default } from "./as-filter-input-P1i0CW2-.mjs";
19
+ import { t as as_table_cell_value_default } from "./as-table-cell-value-B1CiJYFn.mjs";
20
+ import { t as as_table_header_cell_default } from "./as-table-header-cell-CBn_ioCe.mjs";
21
+ import { t as as_window_table_default } from "./as-window-table-CKIfo3M_.mjs";
22
+ import "./as-table-base-D0k4k7k_.mjs";
23
+ import { t as as_filters_default } from "./as-filters-Bxa9ZEMm.mjs";
24
+ import "./preset-aspect-display-BYeiSgcc.mjs";
25
+ import { t as as_preset_dialog_default } from "./as-preset-dialog-BdDRgwf_.mjs";
26
+ import "./as-action-menu-content-CXsdPn42.mjs";
27
+ import { t as as_row_actions_default } from "./as-row-actions-CeWBBGqh.mjs";
28
+ import { t as as_table_root_default } from "./as-table-root-gG7pTIdD.mjs";
29
+ import { t as as_table_default } from "./as-table-Cnw2fOqZ.mjs";
30
+ import { t as as_table_actions_default } from "./as-table-actions-BpMiNFni.mjs";
31
+ import { t as as_preset_picker_default } from "./as-preset-picker-BQbNEiy9.mjs";
32
+ import { getDefaultClientFactory, resetDefaultClientFactory, setDefaultClientFactory } from "@atscript/ui";
33
+ import { computed, effectScope, ref, shallowRef } from "vue";
34
+ import { AppPrefsClient, PRESET_ASPECTS, STANDARD_PRESET_ID, SYSTEM_PRESET_PREFIX, columnFilterType, conditionsForType, defaultCondition, isAuthError, isFilled, isSystemPresetId, resolveSystemPresets } from "@atscript/ui-table";
35
+ import { StorageSerializers, useEventBus, useStorage } from "@vueuse/core";
36
+ //#region src/composables/use-table-filter.ts
37
+ /**
38
+ * Per-field filter state composable.
39
+ *
40
+ * Creates a working copy of filter conditions (cancel-safe dialog model).
41
+ * Call `apply()` to commit, `reset()` to revert, `clear()` to remove.
42
+ *
43
+ * Accepts `state` directly rather than injecting — safe to call outside `setup`.
44
+ */
45
+ function useTableFilter(column, state) {
46
+ const filterType = columnFilterType(column.type);
47
+ const availableConditions = conditionsForType(filterType, column.nullable);
48
+ const defCondition = defaultCondition(filterType);
49
+ function cloneConditions() {
50
+ const existing = state.filters.value[column.path];
51
+ if (existing && existing.length > 0) return existing.map((c) => ({
52
+ type: c.type,
53
+ value: [...c.value]
54
+ }));
55
+ return [{
56
+ type: defCondition,
57
+ value: []
58
+ }];
59
+ }
60
+ const conditions = ref(cloneConditions());
61
+ const filledCount = computed(() => conditions.value.filter(isFilled).length);
62
+ function addCondition() {
63
+ conditions.value = [...conditions.value, {
64
+ type: defCondition,
65
+ value: []
66
+ }];
67
+ }
68
+ function removeCondition(index) {
69
+ conditions.value = conditions.value.filter((_, i) => i !== index);
70
+ if (conditions.value.length === 0) conditions.value = [{
71
+ type: defCondition,
72
+ value: []
73
+ }];
74
+ }
75
+ function updateCondition(index, update) {
76
+ conditions.value = conditions.value.map((c, i) => i === index ? {
77
+ ...c,
78
+ ...update
79
+ } : c);
80
+ }
81
+ function apply() {
82
+ state.setFieldFilter(column.path, conditions.value);
83
+ }
84
+ function clear() {
85
+ state.removeFieldFilter(column.path);
86
+ conditions.value = [{
87
+ type: defCondition,
88
+ value: []
89
+ }];
90
+ }
91
+ function reset() {
92
+ conditions.value = cloneConditions();
93
+ }
94
+ return {
95
+ filterType,
96
+ availableConditions,
97
+ defaultCondition: defCondition,
98
+ conditions,
99
+ filledCount,
100
+ addCondition,
101
+ removeCondition,
102
+ updateCondition,
103
+ apply,
104
+ clear,
105
+ reset
106
+ };
107
+ }
108
+ //#endregion
109
+ //#region src/composables/use-table-search.ts
110
+ /**
111
+ * Convenience composable for wiring a search input to the table.
112
+ * Must be called inside an `<AsTableRoot>` subtree.
113
+ *
114
+ * Returns the reactive `searchTerm` ref and an `onSearchInput` handler.
115
+ * The central filter/search watcher debounces the auto-query.
116
+ */
117
+ function useTableSearch() {
118
+ const { state } = useTableContext();
119
+ function onSearchInput(event) {
120
+ state.searchTerm.value = event.target.value;
121
+ }
122
+ return {
123
+ searchTerm: state.searchTerm,
124
+ onSearchInput
125
+ };
126
+ }
127
+ //#endregion
128
+ //#region src/composables/use-table-actions.ts
129
+ /**
130
+ * Inject the table-actions namespace from the closest `<AsTableRoot>` ancestor.
131
+ * Returns `state.actions` directly — no wrapping. Throws when called outside
132
+ * the provider tree (delegated to `useTableContext`).
133
+ *
134
+ * Useful for consumers that want the model without the chrome (custom
135
+ * toolbars, headless action buttons, programmatic invoke).
136
+ */
137
+ function useTableActions() {
138
+ return useTableContext().state.actions;
139
+ }
140
+ //#endregion
141
+ //#region src/composables/use-table-url-query.ts
142
+ /**
143
+ * Split a uniqu URL string on top-level `&` separators, respecting
144
+ * single-quoted string literals (`name='foo&bar'` is one segment, not two).
145
+ * Within a quote, `\'` escapes a literal apostrophe per @uniqu/url's encoder.
146
+ * Empty segments (from leading/trailing/double `&`) are dropped.
147
+ */
148
+ function splitSegments(urlString) {
149
+ if (!urlString) return [];
150
+ const out = [];
151
+ let start = 0;
152
+ let inQuote = false;
153
+ const push = (end) => {
154
+ if (end > start) out.push(urlString.slice(start, end));
155
+ };
156
+ for (let i = 0; i < urlString.length; i++) {
157
+ const c = urlString[i];
158
+ if (c === "\\" && inQuote) {
159
+ i++;
160
+ continue;
161
+ }
162
+ if (c === "'") inQuote = !inQuote;
163
+ else if (c === "&" && !inQuote) {
164
+ push(i);
165
+ start = i + 1;
166
+ }
167
+ }
168
+ push(urlString.length);
169
+ return out;
170
+ }
171
+ const KEY_CHAR = /[A-Za-z0-9_.$-]/;
172
+ /**
173
+ * Index of `=` if every char before it is URL-key-safe. Returns -1 when any
174
+ * non-key char (uniqu operator, whitespace, etc.) appears first — those
175
+ * segments must round-trip as a single bare key because vue-router's `query`
176
+ * record has no encoding for non-`=` separators.
177
+ */
178
+ function findCleanEq(segment) {
179
+ for (let i = 0; i < segment.length; i++) {
180
+ const c = segment[i];
181
+ if (c === "=") return i > 0 ? i : -1;
182
+ if (!KEY_CHAR.test(c)) return -1;
183
+ }
184
+ return -1;
185
+ }
186
+ /**
187
+ * Bridge `<AsTableRoot v-model:url-query>` to vue-router. Uses **type-only**
188
+ * imports of `Router` and `RouteLocationNormalizedLoaded` — no runtime
189
+ * dependency on `vue-router` is added to `@atscript/vue-table`. Consumers
190
+ * pass in their already-resolved `useRoute()` and `useRouter()` instances.
191
+ *
192
+ * Scope: **owns the whole query string**. The getter returns the entire
193
+ * `route.query` serialized; the setter replaces `route.query` wholesale.
194
+ * Apps that need the table to coexist with non-table query params should
195
+ * write their own `computed` instead — that pattern is small and keeps the
196
+ * library's contract crisp.
197
+ *
198
+ * @example
199
+ * ```vue
200
+ * <script setup>
201
+ * import { useRoute, useRouter } from 'vue-router';
202
+ * import { useTableUrlQuery } from '@atscript/vue-table';
203
+ * const urlQuery = useTableUrlQuery(useRoute(), useRouter());
204
+ * <\/script>
205
+ * <template>
206
+ * <AsTableRoot v-model:url-query="urlQuery" url="/db/products" .../>
207
+ * </template>
208
+ * ```
209
+ */
210
+ function useTableUrlQuery(route, router, opts = {}) {
211
+ const navigate = (opts.mode ?? "replace") === "push" ? router.push.bind(router) : router.replace.bind(router);
212
+ return computed({
213
+ get: () => {
214
+ const q = route.query;
215
+ const parts = [];
216
+ for (const key in q) {
217
+ const v = q[key];
218
+ if (Array.isArray(v)) for (const item of v) parts.push(item == null ? key : `${key}=${item}`);
219
+ else if (v == null) parts.push(key);
220
+ else parts.push(`${key}=${v}`);
221
+ }
222
+ return parts.join("&");
223
+ },
224
+ set: (urlString) => {
225
+ const query = {};
226
+ for (const segment of splitSegments(urlString)) {
227
+ const eqIdx = findCleanEq(segment);
228
+ if (eqIdx > 0) query[segment.slice(0, eqIdx)] = segment.slice(eqIdx + 1);
229
+ else query[segment] = null;
230
+ }
231
+ navigate({ query });
232
+ }
233
+ });
234
+ }
235
+ //#endregion
236
+ //#region src/composables/use-app-prefs.ts
237
+ const APP_PREFS_BUS = Symbol("as-app-prefs");
238
+ const CACHE_PREFIX = "as-app-prefs";
239
+ const REGISTRY = /* @__PURE__ */ new Map();
240
+ function instanceKey(app, url) {
241
+ return `${app}|${url}`;
242
+ }
243
+ /**
244
+ * Public dev-facing composable for app-wide user preferences. Independent
245
+ * of presets / tables — devs can use it on any settings surface to read
246
+ * and write `appearance`, `language`, `density`, `customJson` etc. for
247
+ * `(currentUser, app)`.
248
+ *
249
+ * Multiple calls with the same `(app, url)` share one underlying instance,
250
+ * so duplicate widgets (sidebar + page header + /preferences) make a single
251
+ * `/query?type=appConf` request total.
252
+ *
253
+ * @example
254
+ * ```ts
255
+ * const { prefs, save } = useAppPrefs({ url: "/db/_presets" })
256
+ * // prefs.value.appearance is reactive in templates
257
+ * await save({ appearance: "dark" })
258
+ * ```
259
+ */
260
+ function useAppPrefs(opts) {
261
+ const app = injectPresetsApp(opts.app);
262
+ const key = instanceKey(app, opts.url);
263
+ const existing = REGISTRY.get(key);
264
+ if (existing) {
265
+ const requested = opts.cache !== false;
266
+ if (requested !== existing.cacheEnabled) console.warn(`[vue-table] useAppPrefs("${app}", "${opts.url}"): cache=${requested} ignored — first caller registered cache=${existing.cacheEnabled}.`);
267
+ return existing.public;
268
+ }
269
+ const instance = createInstance(app, opts);
270
+ REGISTRY.set(key, instance);
271
+ return instance.public;
272
+ }
273
+ function createInstance(app, opts) {
274
+ const scope = effectScope(true);
275
+ return scope.run(() => {
276
+ const cacheEnabled = opts.cache !== false;
277
+ const client = new AppPrefsClient({
278
+ url: opts.url,
279
+ app,
280
+ clientFactory: opts.clientFactory
281
+ });
282
+ const cacheKey = `${CACHE_PREFIX}:${app}`;
283
+ const cache = cacheEnabled ? useStorage(cacheKey, null, void 0, {
284
+ listenToStorageChanges: true,
285
+ serializer: StorageSerializers.object,
286
+ flush: "sync"
287
+ }) : ref(null);
288
+ function clearCache() {
289
+ cache.value = null;
290
+ if (cacheEnabled) try {
291
+ globalThis.localStorage?.removeItem(cacheKey);
292
+ } catch {}
293
+ }
294
+ const prefs = computed({
295
+ get: () => cache.value ?? {},
296
+ set: (value) => {
297
+ cache.value = value;
298
+ }
299
+ });
300
+ const existing = shallowRef(null);
301
+ const loading = ref(false);
302
+ const error = ref(null);
303
+ const denied = ref(false);
304
+ const available = computed(() => !denied.value);
305
+ const channel = createChannel(app);
306
+ async function reload() {
307
+ loading.value = true;
308
+ error.value = null;
309
+ try {
310
+ const result = await client.load();
311
+ if (result.denied) {
312
+ denied.value = true;
313
+ clearCache();
314
+ existing.value = null;
315
+ return;
316
+ }
317
+ denied.value = false;
318
+ cache.value = { ...result.prefs };
319
+ existing.value = result.row;
320
+ } catch (err) {
321
+ if (isAuthError(err)) {
322
+ denied.value = true;
323
+ clearCache();
324
+ existing.value = null;
325
+ return;
326
+ }
327
+ error.value = err;
328
+ console.warn("[vue-table] useAppPrefs load failed:", err);
329
+ } finally {
330
+ loading.value = false;
331
+ }
332
+ }
333
+ async function save(patch) {
334
+ const prev = { ...prefs.value };
335
+ cache.value = {
336
+ ...prev,
337
+ ...patch
338
+ };
339
+ try {
340
+ const id = await client.save(existing.value, patch);
341
+ if (!existing.value && id) existing.value = {
342
+ id,
343
+ type: "appConf",
344
+ app,
345
+ user: "",
346
+ data: { ...prefs.value },
347
+ createdAt: 0,
348
+ updatedAt: 0
349
+ };
350
+ const snapshot = { ...prefs.value };
351
+ bus.emit({
352
+ app,
353
+ prefs: snapshot,
354
+ row: existing.value
355
+ });
356
+ channel?.postMessage({
357
+ type: "save",
358
+ prefs: snapshot,
359
+ row: existing.value
360
+ });
361
+ } catch (err) {
362
+ cache.value = prev;
363
+ throw err;
364
+ }
365
+ }
366
+ function reset() {
367
+ clearCache();
368
+ existing.value = null;
369
+ error.value = null;
370
+ denied.value = false;
371
+ bus.emit({
372
+ app,
373
+ reset: true
374
+ });
375
+ channel?.postMessage({ type: "reset" });
376
+ }
377
+ const bus = useEventBus(APP_PREFS_BUS);
378
+ bus.on((payload) => {
379
+ if (payload.app !== app) return;
380
+ if ("reset" in payload) {
381
+ clearCache();
382
+ existing.value = null;
383
+ return;
384
+ }
385
+ cache.value = { ...payload.prefs };
386
+ if (payload.row && !existing.value) existing.value = payload.row;
387
+ });
388
+ channel?.addEventListener("message", (e) => {
389
+ const msg = e.data;
390
+ if (!msg || typeof msg !== "object") return;
391
+ if (msg.type === "reset") {
392
+ clearCache();
393
+ existing.value = null;
394
+ return;
395
+ }
396
+ if (msg.type === "save") {
397
+ cache.value = { ...msg.prefs };
398
+ if (msg.row && !existing.value) existing.value = msg.row;
399
+ }
400
+ });
401
+ if (opts.autoLoad !== false && typeof window !== "undefined") reload();
402
+ return {
403
+ cacheEnabled,
404
+ public: {
405
+ prefs,
406
+ loading,
407
+ error,
408
+ available,
409
+ reload,
410
+ save,
411
+ reset
412
+ },
413
+ dispose() {
414
+ channel?.close();
415
+ scope.stop();
416
+ }
417
+ };
418
+ });
419
+ }
420
+ function createChannel(app) {
421
+ if (typeof window === "undefined") return null;
422
+ if (typeof BroadcastChannel !== "function") return null;
423
+ try {
424
+ return new BroadcastChannel(`as-app-prefs:${app}`);
425
+ } catch {
426
+ return null;
427
+ }
428
+ }
429
+ //#endregion
430
+ //#region src/composables/use-table-component.ts
431
+ /** Resolve a single skin-slot component from the injected `controls` map, falling back to the default. */
432
+ function useTableComponent(key, fallback) {
433
+ const { controls } = useTableContext();
434
+ return controls[key] ?? fallback;
435
+ }
436
+ //#endregion
437
+ //#region src/composables/create-default-controls.ts
438
+ /**
439
+ * Returns a fresh skin-slot map pre-filled with all built-in defaults.
440
+ *
441
+ * Spread or assign additional entries to override specific pieces:
442
+ * ```ts
443
+ * const controls = { ...createDefaultControls(), filterDialog: MyFilterDialog }
444
+ * ```
445
+ *
446
+ * `actionFormDialog` is intentionally not seeded — the table root
447
+ * lazy-mounts it only when an `@InputForm` action is detected. To override
448
+ * or eager-load, import from `@atscript/vue-table/as-action-form-dialog`
449
+ * and assign it as the `actionFormDialog` entry on this map.
450
+ */
451
+ function createDefaultControls() {
452
+ return {
453
+ headerCell: as_table_header_cell_default,
454
+ columnMenu: as_column_menu_default,
455
+ filterDialog: as_filter_dialog_default,
456
+ filterInput: as_filter_input_default,
457
+ filterField: as_filter_field_default,
458
+ configDialog: as_config_dialog_default,
459
+ confirmDialog: as_confirm_dialog_default,
460
+ rowActions: as_row_actions_default
461
+ };
462
+ }
463
+ //#endregion
464
+ //#region src/composables/create-default-cell-types.ts
465
+ /**
466
+ * Returns a fresh cell-type-to-component map pre-filled with the built-in
467
+ * defaults. Spread to extend or override:
468
+ * ```ts
469
+ * const types = { ...createDefaultCellTypes(), status: StatusBadgeCell }
470
+ * ```
471
+ */
472
+ function createDefaultCellTypes() {
473
+ return {
474
+ text: as_table_cell_value_default,
475
+ number: as_cell_number_default,
476
+ boolean: as_table_cell_value_default,
477
+ date: as_cell_date_default,
478
+ datetime: as_cell_date_default,
479
+ relative: as_cell_date_default,
480
+ array: as_cell_array_default,
481
+ object: as_cell_json_default,
482
+ union: as_cell_union_default,
483
+ enum: as_table_cell_value_default,
484
+ ref: as_table_cell_value_default,
485
+ [ROW_ACTIONS_TYPE]: as_row_actions_default
486
+ };
487
+ }
488
+ //#endregion
489
+ //#region src/utils/column-width.ts
490
+ const DEFAULT_WIDTHS = {
491
+ boolean: "5em",
492
+ number: "10em",
493
+ date: "13em",
494
+ datetime: "16em",
495
+ relative: "11em",
496
+ text: "15em",
497
+ array: "18em",
498
+ object: "18em"
499
+ };
500
+ /** Returns column width from annotation or type-based default. */
501
+ function getColumnWidth(column) {
502
+ return column.width || DEFAULT_WIDTHS[column.type] || "15em";
503
+ }
504
+ //#endregion
505
+ export { AS_PRESETS_APP, as_cell_array_default as AsCellArray, as_cell_date_default as AsCellDate, as_cell_json_default as AsCellJson, as_cell_number_default as AsCellNumber, as_column_menu_default as AsColumnMenu, as_config_dialog_default as AsConfigDialog, as_filter_dialog_default as AsFilterDialog, as_filter_field_default as AsFilterField, as_filter_input_default as AsFilterInput, as_filters_default as AsFilters, as_preset_dialog_default as AsPresetDialog, as_preset_picker_default as AsPresetPicker, as_row_actions_default as AsRowActions, as_table_default as AsTable, as_table_actions_default as AsTableActions, as_table_cell_value_default as AsTableCellValue, as_table_header_cell_default as AsTableHeaderCell, as_table_root_default as AsTableRoot, as_window_table_default as AsWindowTable, PRESET_ASPECTS, STANDARD_PRESET_ID, SYSTEM_PRESET_PREFIX, clearTableCache, createDefaultCellTypes, createDefaultControls, createStaticTableState, createTableState, extractIdentifier, formatCellValue, getCellValue, getColumnWidth, getDefaultClientFactory, injectPresetsApp, isSystemPresetId, provideCellLocale, resetDefaultClientFactory, resolveSystemPresets, setDefaultClientFactory, useAppPrefs, useCellLocale, useLocalDraft, usePresets, useTable, useTableActions, useTableComponent, useTableContext, useTableContextOptional, useTableFilter, useTableNavBridge, useTableSearch, useTableSelection, useTableUrlQuery };
@@ -0,0 +1,43 @@
1
+ import { derivePresetAspects } from "@atscript/ui-table";
2
+ //#region src/composables/preset-aspect-display.ts
3
+ const ASPECT_LABELS = {
4
+ columns: "Displayed Columns",
5
+ filters: "Displayed Filters",
6
+ filterOps: "Filter conditions",
7
+ sorters: "Sorters",
8
+ itemsPerPage: "Page size"
9
+ };
10
+ const ASPECT_ICONS = {
11
+ columns: "i-as-columns",
12
+ filters: "i-as-filter",
13
+ filterOps: "i-as-filter-ops",
14
+ sorters: "i-as-sorters",
15
+ itemsPerPage: "i-as-pin"
16
+ };
17
+ /**
18
+ * Resolve the aspects a stored preset claims. Prefers the server-stamped
19
+ * `aspects` column (cheap), falls back to deriving from `data.content` for
20
+ * older rows or first paint after save before reload settles.
21
+ */
22
+ function aspectsOf(row, availableAspects) {
23
+ if (Array.isArray(row.aspects) && row.aspects.length > 0) return row.aspects.filter((a) => availableAspects.includes(a));
24
+ const wire = row.data?.content;
25
+ if (!wire) return [];
26
+ return derivePresetAspects(wire).filter((a) => availableAspects.includes(a));
27
+ }
28
+ function readPresetLabel(row) {
29
+ return row.label ?? row.data?.label ?? row.id;
30
+ }
31
+ /**
32
+ * Display name for the row's owner. `userLabel` (server-stamped via the
33
+ * host's `getUserLabel` hook) is preferred so the UI shows "Alice" rather
34
+ * than `usr_abc123`. `fallback` is returned when no name is available —
35
+ * picker uses `""`, dialog uses `"—"`.
36
+ */
37
+ function ownerNameOf(row, fallback = "") {
38
+ if (typeof row.userLabel === "string" && row.userLabel.length > 0) return row.userLabel;
39
+ if (typeof row.user === "string" && row.user.length > 0) return row.user;
40
+ return fallback;
41
+ }
42
+ //#endregion
43
+ export { readPresetLabel as a, ownerNameOf as i, ASPECT_LABELS as n, aspectsOf as r, ASPECT_ICONS as t };
@@ -0,0 +1,72 @@
1
+ let _atscript_ui_table = require("@atscript/ui-table");
2
+ //#region src/composables/preset-aspect-display.ts
3
+ const ASPECT_LABELS = {
4
+ columns: "Displayed Columns",
5
+ filters: "Displayed Filters",
6
+ filterOps: "Filter conditions",
7
+ sorters: "Sorters",
8
+ itemsPerPage: "Page size"
9
+ };
10
+ const ASPECT_ICONS = {
11
+ columns: "i-as-columns",
12
+ filters: "i-as-filter",
13
+ filterOps: "i-as-filter-ops",
14
+ sorters: "i-as-sorters",
15
+ itemsPerPage: "i-as-pin"
16
+ };
17
+ /**
18
+ * Resolve the aspects a stored preset claims. Prefers the server-stamped
19
+ * `aspects` column (cheap), falls back to deriving from `data.content` for
20
+ * older rows or first paint after save before reload settles.
21
+ */
22
+ function aspectsOf(row, availableAspects) {
23
+ if (Array.isArray(row.aspects) && row.aspects.length > 0) return row.aspects.filter((a) => availableAspects.includes(a));
24
+ const wire = row.data?.content;
25
+ if (!wire) return [];
26
+ return (0, _atscript_ui_table.derivePresetAspects)(wire).filter((a) => availableAspects.includes(a));
27
+ }
28
+ function readPresetLabel(row) {
29
+ return row.label ?? row.data?.label ?? row.id;
30
+ }
31
+ /**
32
+ * Display name for the row's owner. `userLabel` (server-stamped via the
33
+ * host's `getUserLabel` hook) is preferred so the UI shows "Alice" rather
34
+ * than `usr_abc123`. `fallback` is returned when no name is available —
35
+ * picker uses `""`, dialog uses `"—"`.
36
+ */
37
+ function ownerNameOf(row, fallback = "") {
38
+ if (typeof row.userLabel === "string" && row.userLabel.length > 0) return row.userLabel;
39
+ if (typeof row.user === "string" && row.user.length > 0) return row.user;
40
+ return fallback;
41
+ }
42
+ //#endregion
43
+ Object.defineProperty(exports, "ASPECT_ICONS", {
44
+ enumerable: true,
45
+ get: function() {
46
+ return ASPECT_ICONS;
47
+ }
48
+ });
49
+ Object.defineProperty(exports, "ASPECT_LABELS", {
50
+ enumerable: true,
51
+ get: function() {
52
+ return ASPECT_LABELS;
53
+ }
54
+ });
55
+ Object.defineProperty(exports, "aspectsOf", {
56
+ enumerable: true,
57
+ get: function() {
58
+ return aspectsOf;
59
+ }
60
+ });
61
+ Object.defineProperty(exports, "ownerNameOf", {
62
+ enumerable: true,
63
+ get: function() {
64
+ return ownerNameOf;
65
+ }
66
+ });
67
+ Object.defineProperty(exports, "readPresetLabel", {
68
+ enumerable: true,
69
+ get: function() {
70
+ return readPresetLabel;
71
+ }
72
+ });