@chelone/core 0.6.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/dist/assistant/assistant-session.d.ts +6 -0
  2. package/dist/assistant/assistant-session.js +204 -181
  3. package/dist/assistant/echo-transport.js +26 -29
  4. package/dist/assistant/http-transport.d.ts +10 -0
  5. package/dist/assistant/http-transport.js +98 -0
  6. package/dist/assistant/types.d.ts +1 -7
  7. package/dist/auth/access-control.d.ts +13 -5
  8. package/dist/auth/access-control.js +25 -21
  9. package/dist/auth/auth-options.d.ts +23 -17
  10. package/dist/auth/auth-options.js +82 -48
  11. package/dist/auth/permission-matrix.d.ts +12 -0
  12. package/dist/auth/permission-matrix.js +67 -0
  13. package/dist/auth/types.d.ts +14 -4
  14. package/dist/block-editor/block-document.d.ts +64 -0
  15. package/dist/block-editor/block-document.js +147 -0
  16. package/dist/block-editor/data-blocks.d.ts +63 -0
  17. package/dist/block-editor/data-blocks.js +117 -0
  18. package/dist/chart/chart-data.js +46 -44
  19. package/dist/command-menu/hotkey.js +58 -47
  20. package/dist/command-menu/recents.d.ts +4 -0
  21. package/dist/command-menu/recents.js +12 -11
  22. package/dist/command-menu/registry.d.ts +9 -5
  23. package/dist/command-menu/registry.js +36 -46
  24. package/dist/controller/calendar-dates.d.ts +12 -0
  25. package/dist/controller/calendar-dates.js +94 -113
  26. package/dist/controller/calendar-events.js +93 -88
  27. package/dist/controller/client-list-controller.d.ts +2 -2
  28. package/dist/controller/client-list-controller.js +251 -254
  29. package/dist/controller/data-table-columns.d.ts +2 -0
  30. package/dist/controller/data-table-columns.js +50 -56
  31. package/dist/controller/deep-equal.d.ts +1 -0
  32. package/dist/controller/deep-equal.js +14 -0
  33. package/dist/controller/filter-toggle.js +36 -44
  34. package/dist/controller/in-place-editor.d.ts +43 -0
  35. package/dist/controller/in-place-editor.js +43 -0
  36. package/dist/controller/infinite-list-controller.js +219 -189
  37. package/dist/controller/inspector.d.ts +55 -0
  38. package/dist/controller/inspector.js +70 -0
  39. package/dist/controller/job-monitor.d.ts +10 -4
  40. package/dist/controller/job-monitor.js +46 -47
  41. package/dist/controller/kanban-board.js +45 -24
  42. package/dist/controller/list-controller.d.ts +8 -5
  43. package/dist/controller/list-controller.js +447 -400
  44. package/dist/controller/list-params.js +96 -87
  45. package/dist/controller/pivot-grid.d.ts +4 -4
  46. package/dist/controller/pivot-grid.js +89 -95
  47. package/dist/controller/prev-next.d.ts +2 -2
  48. package/dist/controller/prev-next.js +74 -54
  49. package/dist/controller/record-controllers.d.ts +14 -6
  50. package/dist/controller/record-controllers.js +288 -257
  51. package/dist/controller/record-diff.d.ts +21 -0
  52. package/dist/controller/record-diff.js +50 -0
  53. package/dist/controller/record-timeline.d.ts +5 -5
  54. package/dist/controller/record-timeline.js +42 -30
  55. package/dist/controller/record-tree.js +57 -47
  56. package/dist/controller/record-workflow.d.ts +38 -16
  57. package/dist/controller/record-workflow.js +85 -64
  58. package/dist/controller/reference-many-controller.d.ts +2 -0
  59. package/dist/controller/reference-many-controller.js +199 -192
  60. package/dist/controller/reference-one-controller.d.ts +1 -1
  61. package/dist/controller/reference-one-controller.js +63 -56
  62. package/dist/controller/saved-queries.js +104 -91
  63. package/dist/controller/translate-fallback.js +10 -6
  64. package/dist/csv/export.d.ts +4 -3
  65. package/dist/csv/export.js +43 -40
  66. package/dist/csv/import-controller.d.ts +4 -0
  67. package/dist/csv/import-controller.js +189 -169
  68. package/dist/csv/match-headers.js +29 -22
  69. package/dist/csv/parse-with.js +60 -54
  70. package/dist/csv/run-import.js +69 -72
  71. package/dist/csv/validate-rows.d.ts +1 -1
  72. package/dist/csv/validate-rows.js +65 -52
  73. package/dist/data/cache-ops.d.ts +5 -4
  74. package/dist/data/cache-ops.js +208 -188
  75. package/dist/data/combine-data-providers.js +25 -23
  76. package/dist/data/data-provider-log.d.ts +45 -0
  77. package/dist/data/data-provider-log.js +93 -0
  78. package/dist/data/errors.js +14 -10
  79. package/dist/data/fake-provider.d.ts +6 -3
  80. package/dist/data/fake-provider.js +135 -114
  81. package/dist/data/fetch-utils.js +61 -44
  82. package/dist/data/filter-branch.d.ts +5 -0
  83. package/dist/data/filter-branch.js +10 -0
  84. package/dist/data/get-many-aggregate.js +84 -76
  85. package/dist/data/http-error.js +17 -12
  86. package/dist/data/keys.js +50 -36
  87. package/dist/data/mutation-options.d.ts +14 -9
  88. package/dist/data/mutation-options.js +93 -109
  89. package/dist/data/query-options.js +73 -68
  90. package/dist/data/remove-empty.d.ts +3 -0
  91. package/dist/data/remove-empty.js +11 -0
  92. package/dist/data/undoable.d.ts +2 -2
  93. package/dist/data/undoable.js +190 -174
  94. package/dist/data/with-lifecycle-callbacks.d.ts +45 -17
  95. package/dist/data/with-lifecycle-callbacks.js +66 -52
  96. package/dist/environment/application-update-store.js +58 -55
  97. package/dist/environment/offline-store.js +21 -21
  98. package/dist/form/array-binding.d.ts +30 -11
  99. package/dist/form/array-binding.js +184 -166
  100. package/dist/form/choice-ids.d.ts +7 -0
  101. package/dist/form/choice-ids.js +11 -0
  102. package/dist/form/choices-controller.d.ts +22 -2
  103. package/dist/form/choices-controller.js +315 -275
  104. package/dist/form/date-format.d.ts +38 -0
  105. package/dist/form/date-format.js +89 -0
  106. package/dist/form/dirty-values.d.ts +2 -2
  107. package/dist/form/dirty-values.js +22 -11
  108. package/dist/form/duration.d.ts +22 -0
  109. package/dist/form/duration.js +49 -0
  110. package/dist/form/edit-create-form.d.ts +12 -5
  111. package/dist/form/edit-create-form.js +243 -188
  112. package/dist/form/event-value.d.ts +6 -0
  113. package/dist/form/event-value.js +17 -0
  114. package/dist/form/field-error.d.ts +14 -0
  115. package/dist/form/field-error.js +28 -0
  116. package/dist/form/field-name.d.ts +20 -0
  117. package/dist/form/field-name.js +6 -0
  118. package/dist/form/filter-form-values.js +63 -49
  119. package/dist/form/form-controller.d.ts +9 -1
  120. package/dist/form/form-controller.js +165 -160
  121. package/dist/form/form-groups.d.ts +4 -3
  122. package/dist/form/form-groups.js +79 -79
  123. package/dist/form/form-handle.d.ts +175 -0
  124. package/dist/form/form-handle.js +68 -0
  125. package/dist/form/input-binding.d.ts +56 -31
  126. package/dist/form/input-binding.js +171 -118
  127. package/dist/form/input-values.d.ts +140 -0
  128. package/dist/form/input-values.js +206 -0
  129. package/dist/form/json-text.d.ts +11 -0
  130. package/dist/form/json-text.js +62 -37
  131. package/dist/form/save-pipeline.d.ts +6 -8
  132. package/dist/form/save-pipeline.js +91 -82
  133. package/dist/form/set-form-values.d.ts +6 -0
  134. package/dist/form/set-form-values.js +10 -0
  135. package/dist/form/source.js +97 -65
  136. package/dist/form/text-of.d.ts +2 -0
  137. package/dist/form/text-of.js +7 -0
  138. package/dist/form/validators.d.ts +58 -19
  139. package/dist/form/validators.js +97 -71
  140. package/dist/geo/bbox.d.ts +5 -4
  141. package/dist/geo/bbox.js +69 -48
  142. package/dist/geo/bounds.d.ts +14 -3
  143. package/dist/geo/bounds.js +98 -68
  144. package/dist/geo/constraints.js +88 -93
  145. package/dist/geo/coordinates.d.ts +10 -0
  146. package/dist/geo/coordinates.js +44 -23
  147. package/dist/geo/editor.d.ts +13 -13
  148. package/dist/geo/editor.js +176 -153
  149. package/dist/geo/geocoding.d.ts +4 -4
  150. package/dist/geo/geocoding.js +38 -41
  151. package/dist/geo/geojson.d.ts +12 -74
  152. package/dist/geo/geojson.js +52 -40
  153. package/dist/geo/geometry-math.d.ts +4 -4
  154. package/dist/geo/geometry-math.js +100 -93
  155. package/dist/geo/index.d.ts +9 -8
  156. package/dist/geo/map-layers.d.ts +42 -7
  157. package/dist/geo/map-layers.js +88 -62
  158. package/dist/geo/map-style.d.ts +12 -0
  159. package/dist/geo/map-style.js +43 -32
  160. package/dist/geo/messages.js +48 -45
  161. package/dist/geo/nominatim.js +88 -80
  162. package/dist/geo/osm-presets.d.ts +4 -3
  163. package/dist/geo/osm-presets.js +108 -86
  164. package/dist/geo/osm-tags.js +14 -12
  165. package/dist/geo/overpass.d.ts +14 -2
  166. package/dist/geo/overpass.js +83 -90
  167. package/dist/geo/shape-value.d.ts +9 -5
  168. package/dist/geo/shape-value.js +169 -146
  169. package/dist/geo/snap-to-roads.d.ts +3 -3
  170. package/dist/geo/snap-to-roads.js +55 -50
  171. package/dist/geo/throttle.js +36 -39
  172. package/dist/guards.d.ts +44 -0
  173. package/dist/guards.js +77 -0
  174. package/dist/i18n/default-messages.js +34 -29
  175. package/dist/i18n/english-messages.d.ts +172 -0
  176. package/dist/i18n/english-messages.js +359 -189
  177. package/dist/i18n/i18n.d.ts +2 -2
  178. package/dist/i18n/i18n.js +47 -60
  179. package/dist/i18n/inflection.d.ts +34 -0
  180. package/dist/i18n/inflection.js +82 -0
  181. package/dist/i18n/messages.d.ts +10 -2
  182. package/dist/i18n/messages.js +17 -4
  183. package/dist/i18n/missing-keys.d.ts +4 -0
  184. package/dist/i18n/missing-keys.js +70 -62
  185. package/dist/i18n/translatable.d.ts +16 -1
  186. package/dist/i18n/translatable.js +40 -47
  187. package/dist/index.d.ts +87 -39
  188. package/dist/index.js +54 -301
  189. package/dist/json/deep-equal.d.ts +8 -0
  190. package/dist/json/deep-equal.js +24 -0
  191. package/dist/json/strip-json-comments.js +38 -42
  192. package/dist/noop.d.ts +2 -0
  193. package/dist/noop.js +4 -0
  194. package/dist/notification/error-message.d.ts +2 -0
  195. package/dist/notification/error-message.js +10 -0
  196. package/dist/notification/notification-store.d.ts +3 -2
  197. package/dist/notification/notification-store.js +41 -45
  198. package/dist/onboarding-tour/placement.d.ts +2 -0
  199. package/dist/onboarding-tour/placement.js +65 -78
  200. package/dist/onboarding-tour/tour-controller.js +46 -54
  201. package/dist/realtime/add-events-for-mutations.js +75 -81
  202. package/dist/realtime/announce-lock.js +16 -13
  203. package/dist/realtime/broadcast-channel-transport.js +65 -59
  204. package/dist/realtime/copy-members.js +22 -14
  205. package/dist/realtime/in-memory-lock-provider.js +40 -48
  206. package/dist/realtime/live.js +95 -101
  207. package/dist/realtime/lock-options.js +16 -16
  208. package/dist/realtime/lock-session.js +91 -78
  209. package/dist/realtime/memory-transport.js +25 -25
  210. package/dist/realtime/presence.js +120 -122
  211. package/dist/realtime/realtime-data-provider.d.ts +10 -0
  212. package/dist/realtime/realtime-data-provider.js +45 -42
  213. package/dist/realtime/reconnect-backoff.js +17 -0
  214. package/dist/realtime/sse-transport.d.ts +31 -0
  215. package/dist/realtime/sse-transport.js +235 -0
  216. package/dist/realtime/status-store.js +23 -28
  217. package/dist/realtime/topic-hub.js +62 -71
  218. package/dist/realtime/topics.js +10 -12
  219. package/dist/realtime/types.js +10 -12
  220. package/dist/realtime/unread-count.js +21 -21
  221. package/dist/realtime/websocket-transport.d.ts +32 -0
  222. package/dist/realtime/websocket-transport.js +306 -0
  223. package/dist/resource/describe-resource.d.ts +2 -0
  224. package/dist/resource/describe-resource.js +247 -219
  225. package/dist/resource/get-at-path.js +29 -14
  226. package/dist/resource/identifier.d.ts +18 -0
  227. package/dist/resource/identifier.js +27 -0
  228. package/dist/resource/record.d.ts +4 -0
  229. package/dist/resource/record.js +10 -0
  230. package/dist/resource/register.d.ts +7 -0
  231. package/dist/resource/registry-store.d.ts +45 -15
  232. package/dist/resource/registry-store.js +67 -60
  233. package/dist/resource/registry.d.ts +10 -0
  234. package/dist/resource/registry.js +8 -4
  235. package/dist/resource/source-path.d.ts +23 -2
  236. package/dist/rich-text/rich-text-extras.d.ts +134 -0
  237. package/dist/rich-text/rich-text-extras.js +181 -0
  238. package/dist/rich-text/rich-text-image.d.ts +124 -0
  239. package/dist/rich-text/rich-text-image.js +163 -0
  240. package/dist/rich-text/rich-text.d.ts +6 -0
  241. package/dist/rich-text/rich-text.js +125 -88
  242. package/dist/router/location.d.ts +24 -4
  243. package/dist/router/location.js +43 -18
  244. package/dist/router/match.js +47 -39
  245. package/dist/router/paths.js +40 -34
  246. package/dist/router/record-from-location.d.ts +1 -1
  247. package/dist/router/record-from-location.js +25 -17
  248. package/dist/store/adapters.js +51 -55
  249. package/dist/store/micro-store.js +57 -59
  250. package/dist/store/shallow-equal.d.ts +12 -0
  251. package/dist/store/shallow-equal.js +20 -0
  252. package/dist/store/store.js +54 -57
  253. package/dist/ui-defaults.d.ts +15 -0
  254. package/dist/ui-defaults.js +17 -0
  255. package/package.json +13 -11
@@ -1,104 +1,117 @@
1
+ import { isPlainObject, isRecord } from "../guards.js";
1
2
  import { createMicroStore } from "../store/micro-store.js";
3
+ // src/controller/saved-queries.ts
4
+ /** The key ra-core's `useSavedQueries` uses. */
2
5
  function savedQueriesKey(storeKey) {
3
- return `${storeKey}.savedQueries`;
6
+ return `${storeKey}.savedQueries`;
4
7
  }
5
- const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
6
- const isSortPayload = (value) => isRecord(value) && typeof value.field === "string" && (value.order === "ASC" || value.order === "DESC");
8
+ var isSortPayload = (value) => isRecord(value) && typeof value.field === "string" && (value.order === "ASC" || value.order === "DESC");
7
9
  function isSavedQueryValue(value) {
8
- return isRecord(value) && isRecord(value.filter) && isRecord(value.displayedFilters) && Object.values(value.displayedFilters).every(
9
- (flag) => typeof flag === "boolean"
10
- ) && Array.isArray(value.sort) && value.sort.every(isSortPayload) && typeof value.perPage === "number" && Number.isInteger(value.perPage) && value.perPage > 0;
10
+ return isRecord(value) && isRecord(value.filter) && isRecord(value.displayedFilters) && Object.values(value.displayedFilters).every((flag) => typeof flag === "boolean") && Array.isArray(value.sort) && value.sort.every(isSortPayload) && typeof value.perPage === "number" && Number.isInteger(value.perPage) && value.perPage > 0;
11
11
  }
12
+ /**
13
+ * Reads whatever storage holds: non-arrays give `[]`, malformed entries are
14
+ * dropped, labels are trimmed, and a repeated label keeps its first entry.
15
+ */
12
16
  function extractValidSavedQueries(raw) {
13
- if (!Array.isArray(raw)) return [];
14
- const seen = /* @__PURE__ */ new Set();
15
- const queries = [];
16
- for (const entry of raw) {
17
- if (!isRecord(entry) || typeof entry.label !== "string") continue;
18
- const label = entry.label.trim();
19
- if (!label || seen.has(label) || !isSavedQueryValue(entry.value)) continue;
20
- seen.add(label);
21
- queries.push({ label, value: entry.value });
22
- }
23
- return queries;
17
+ if (!Array.isArray(raw)) return [];
18
+ const seen = /* @__PURE__ */ new Set();
19
+ const queries = [];
20
+ for (const entry of raw) {
21
+ if (!isRecord(entry) || typeof entry.label !== "string") continue;
22
+ const label = entry.label.trim();
23
+ if (!label || seen.has(label) || !isSavedQueryValue(entry.value)) continue;
24
+ seen.add(label);
25
+ queries.push({
26
+ label,
27
+ value: entry.value
28
+ });
29
+ }
30
+ return queries;
24
31
  }
25
- const isPlainObject = (value) => {
26
- if (!isRecord(value)) return false;
27
- const proto = Object.getPrototypeOf(value);
28
- return proto === Object.prototype || proto === null;
29
- };
32
+ /**
33
+ * Structural equality; object key order is irrelevant, array order is not.
34
+ * Only plain objects, arrays and dates compare by content: any other class
35
+ * instance is equal to itself alone.
36
+ */
30
37
  function isDeepEqual(a, b) {
31
- if (Object.is(a, b)) return true;
32
- if (a instanceof Date || b instanceof Date) {
33
- return a instanceof Date && b instanceof Date && a.getTime() === b.getTime();
34
- }
35
- if (Array.isArray(a) || Array.isArray(b)) {
36
- return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((item, index) => isDeepEqual(item, b[index]));
37
- }
38
- if (!isPlainObject(a) || !isPlainObject(b)) return false;
39
- const keys = Object.keys(a);
40
- return keys.length === Object.keys(b).length && keys.every((key) => key in b && isDeepEqual(a[key], b[key]));
38
+ if (Object.is(a, b)) return true;
39
+ if (a instanceof Date || b instanceof Date) return a instanceof Date && b instanceof Date && a.getTime() === b.getTime();
40
+ if (Array.isArray(a) || Array.isArray(b)) return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((item, index) => isDeepEqual(item, b[index]));
41
+ if (!isPlainObject(a) || !isPlainObject(b)) return false;
42
+ const keys = Object.keys(a);
43
+ return keys.length === Object.keys(b).length && keys.every((key) => key in b && isDeepEqual(a[key], b[key]));
41
44
  }
45
+ /** Whether `current` list params are the saved query. `displayedFilters` is ignored. */
42
46
  function isSavedQueryActive(query, current) {
43
- return query.perPage === current.perPage && isDeepEqual(query.sort, current.sort) && isDeepEqual(query.filter, current.filter);
47
+ return query.perPage === current.perPage && isDeepEqual(query.sort, current.sort) && isDeepEqual(query.filter, current.filter);
44
48
  }
49
+ /**
50
+ * Named filter/sort sets persisted in the KV store.
51
+ *
52
+ * Lifecycle (Task 4R): construction is inert. The first subscriber subscribes
53
+ * to the store key and re-reads it; the last unsubscribe releases it. Detached,
54
+ * a write still updates local state, and the next attach picks up whatever the
55
+ * store holds.
56
+ */
45
57
  function createSavedQueriesController(ctx, resource, options = {}) {
46
- const key = savedQueriesKey(options.storeKey ?? resource);
47
- const kv = ctx.store;
48
- let lastRaw = kv?.getItem(key);
49
- const store = createMicroStore(
50
- { queries: extractValidSavedQueries(lastRaw) },
51
- {
52
- onSubscribed: () => {
53
- if (!kv) return;
54
- resync();
55
- return kv.subscribe(key, resync);
56
- }
57
- }
58
- );
59
- function resync() {
60
- if (!kv) return;
61
- const raw = kv.getItem(key);
62
- if (raw === lastRaw) return;
63
- lastRaw = raw;
64
- const queries = extractValidSavedQueries(raw);
65
- if (isDeepEqual(queries, store.getSnapshot().queries)) return;
66
- store.setState({ queries });
67
- }
68
- const current = () => {
69
- resync();
70
- return store.getSnapshot().queries;
71
- };
72
- const write = (queries) => {
73
- if (!kv) {
74
- store.setState({ queries });
75
- return;
76
- }
77
- kv.setItem(key, queries);
78
- resync();
79
- };
80
- const save = (label, value) => {
81
- const trimmed = label.trim();
82
- if (!trimmed) return;
83
- if (!isSavedQueryValue(value)) return;
84
- const next = { label: trimmed, value: structuredClone(value) };
85
- const queries = current();
86
- const index = queries.findIndex((query) => query.label === trimmed);
87
- write(
88
- index === -1 ? [...queries, next] : queries.map((query, i) => i === index ? next : query)
89
- );
90
- };
91
- const remove = (label) => {
92
- const trimmed = label.trim();
93
- const queries = current();
94
- if (!queries.some((query) => query.label === trimmed)) return;
95
- write(queries.filter((query) => query.label !== trimmed));
96
- };
97
- return { ...store, save, remove };
58
+ const key = savedQueriesKey(options.storeKey ?? resource);
59
+ const kv = ctx.store;
60
+ /** The raw value the state was last derived from, to skip no-op resyncs. */
61
+ let lastRaw = kv?.getItem(key);
62
+ const store = createMicroStore({ queries: extractValidSavedQueries(lastRaw) }, { onSubscribed: () => {
63
+ if (!kv) return;
64
+ resync();
65
+ return kv.subscribe(key, resync);
66
+ } });
67
+ /** Brings state in line with the store; a no-op when nothing changed. */
68
+ function resync() {
69
+ if (!kv) return;
70
+ const raw = kv.getItem(key);
71
+ if (raw === lastRaw) return;
72
+ lastRaw = raw;
73
+ const queries = extractValidSavedQueries(raw);
74
+ if (isDeepEqual(queries, store.getSnapshot().queries)) return;
75
+ store.setState({ queries });
76
+ }
77
+ /**
78
+ * Detached, nothing keeps state current, so every action starts from the
79
+ * store: a stale snapshot would write over another controller's queries.
80
+ */
81
+ const current = () => {
82
+ resync();
83
+ return store.getSnapshot().queries;
84
+ };
85
+ const write = (queries) => {
86
+ if (!kv) {
87
+ store.setState({ queries });
88
+ return;
89
+ }
90
+ kv.setItem(key, queries);
91
+ resync();
92
+ };
93
+ const save = (label, value) => {
94
+ const trimmed = label.trim();
95
+ if (!trimmed) return;
96
+ if (!isSavedQueryValue(value)) return;
97
+ const next = {
98
+ label: trimmed,
99
+ value: structuredClone(value)
100
+ };
101
+ const queries = current();
102
+ const index = queries.findIndex((query) => query.label === trimmed);
103
+ write(index === -1 ? [...queries, next] : queries.map((query, i) => i === index ? next : query));
104
+ };
105
+ const remove = (label) => {
106
+ const trimmed = label.trim();
107
+ const queries = current();
108
+ if (!queries.some((query) => query.label === trimmed)) return;
109
+ write(queries.filter((query) => query.label !== trimmed));
110
+ };
111
+ return {
112
+ ...store,
113
+ save,
114
+ remove
115
+ };
98
116
  }
99
- export {
100
- createSavedQueriesController,
101
- extractValidSavedQueries,
102
- isSavedQueryActive,
103
- savedQueriesKey
104
- };
117
+ export { createSavedQueriesController, extractValidSavedQueries, isSavedQueryActive, savedQueriesKey };
@@ -1,8 +1,12 @@
1
+ // src/controller/translate-fallback.ts
2
+ /**
3
+ * Resource-scoped notification key with global fallback. A translator that
4
+ * returns the key unchanged (Chelone i18n's missing-key behavior) means
5
+ * "not translated" — fall back to the global key.
6
+ */
1
7
  function resolveNotificationKey(translate, resource, event) {
2
- const scoped = `resources.${resource}.notifications.${event}`;
3
- if (translate && translate(scoped) !== scoped) return scoped;
4
- return `chelone.notification.${event}`;
8
+ const scoped = `resources.${resource}.notifications.${event}`;
9
+ if (translate && translate(scoped) !== scoped) return scoped;
10
+ return `chelone.notification.${event}`;
5
11
  }
6
- export {
7
- resolveNotificationKey
8
- };
12
+ export { resolveNotificationKey };
@@ -18,19 +18,20 @@
18
18
  * passes its own `exporter` prop — the button never assumes the default.
19
19
  */
20
20
  import type { DataProvider } from "../data/types.js";
21
- import type { LooseRecord } from "../resource/record.js";
21
+ import type { LooseRecord, ResourceRecord } from "../resource/record.js";
22
+ import type { CsvRow } from "./types.js";
22
23
  /**
23
24
  * Turns a page of records into a downloaded file. Called by the export buttons
24
25
  * with the fetched rows, the raw dataProvider (for follow-up fetches), and the
25
26
  * resource name.
26
27
  */
27
- export type Exporter<TRecord extends LooseRecord = LooseRecord> = (data: TRecord[], dataProvider: DataProvider, resource: string) => void | Promise<void>;
28
+ export type Exporter<TRecord extends ResourceRecord = LooseRecord> = (data: TRecord[], dataProvider: DataProvider, resource: string) => void | Promise<void>;
28
29
  /**
29
30
  * Serialize records to CSV text. Columns are the UNION of every record's keys,
30
31
  * in first-seen order — so a sparse record still lines up under the right
31
32
  * header. Returns an empty string for an empty dataset.
32
33
  */
33
- export declare function recordsToCSV(data: readonly LooseRecord[]): string;
34
+ export declare function recordsToCSV(data: readonly CsvRow[]): string;
34
35
  /**
35
36
  * Trigger a browser download of `csv` as `<filename>.csv`. A DOM-guarded no-op
36
37
  * when there is no `document` (SSR / non-jsdom test env) so callers never crash
@@ -1,47 +1,50 @@
1
+ // src/csv/export.ts
2
+ /** Escape one CSV cell: wrap in quotes + double any embedded quote when needed. */
1
3
  function csvCell(value) {
2
- if (value == null) return "";
3
- const raw = typeof value === "object" ? JSON.stringify(value) : String(value);
4
- if (/[",\n\r]/.test(raw)) {
5
- return `"${raw.replace(/"/g, '""')}"`;
6
- }
7
- return raw;
4
+ if (value == null) return "";
5
+ const raw = typeof value === "object" ? JSON.stringify(value) : String(value);
6
+ if (/[",\n\r]/.test(raw)) return `"${raw.replace(/"/g, "\"\"")}"`;
7
+ return raw;
8
8
  }
9
+ /**
10
+ * Serialize records to CSV text. Columns are the UNION of every record's keys,
11
+ * in first-seen order — so a sparse record still lines up under the right
12
+ * header. Returns an empty string for an empty dataset.
13
+ */
9
14
  function recordsToCSV(data) {
10
- if (data.length === 0) return "";
11
- const columns = [];
12
- const seen = /* @__PURE__ */ new Set();
13
- for (const record of data) {
14
- for (const key of Object.keys(record)) {
15
- if (!seen.has(key)) {
16
- seen.add(key);
17
- columns.push(key);
18
- }
19
- }
20
- }
21
- const header = columns.map(csvCell).join(",");
22
- const rows = data.map(
23
- (record) => columns.map((col) => csvCell(record[col])).join(",")
24
- );
25
- return [header, ...rows].join("\n");
15
+ if (data.length === 0) return "";
16
+ const columns = [];
17
+ const seen = /* @__PURE__ */ new Set();
18
+ for (const record of data) for (const key of Object.keys(record)) if (!seen.has(key)) {
19
+ seen.add(key);
20
+ columns.push(key);
21
+ }
22
+ return [columns.map(csvCell).join(","), ...data.map((record) => columns.map((col) => csvCell(record[col])).join(","))].join("\n");
26
23
  }
24
+ /**
25
+ * Trigger a browser download of `csv` as `<filename>.csv`. A DOM-guarded no-op
26
+ * when there is no `document` (SSR / non-jsdom test env) so callers never crash
27
+ * off-DOM.
28
+ */
27
29
  function downloadCSV(csv, filename) {
28
- if (typeof document === "undefined") return;
29
- const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
30
- const url = URL.createObjectURL(blob);
31
- const link = document.createElement("a");
32
- link.href = url;
33
- link.download = `${filename}.csv`;
34
- link.style.display = "none";
35
- document.body.appendChild(link);
36
- link.click();
37
- document.body.removeChild(link);
38
- setTimeout(() => URL.revokeObjectURL(url), 0);
30
+ if (typeof document === "undefined") return;
31
+ const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
32
+ const url = URL.createObjectURL(blob);
33
+ const link = document.createElement("a");
34
+ link.href = url;
35
+ link.download = `${filename}.csv`;
36
+ link.style.display = "none";
37
+ document.body.appendChild(link);
38
+ link.click();
39
+ document.body.removeChild(link);
40
+ setTimeout(() => URL.revokeObjectURL(url), 0);
39
41
  }
40
- const defaultExporter = (data, _dataProvider, resource) => {
41
- downloadCSV(recordsToCSV(data), resource);
42
- };
43
- export {
44
- defaultExporter,
45
- downloadCSV,
46
- recordsToCSV
42
+ /**
43
+ * The built-in exporter: serialize `data` to CSV (union-of-keys columns) and
44
+ * download it as `<resource>.csv`. Apps needing nested/related data pass a
45
+ * custom `exporter` prop instead.
46
+ */
47
+ var defaultExporter = (data, _dataProvider, resource) => {
48
+ downloadCSV(recordsToCSV(data), resource);
47
49
  };
50
+ export { defaultExporter, downloadCSV, recordsToCSV };
@@ -1,5 +1,9 @@
1
1
  import { type MicroStore } from "../store/micro-store.js";
2
2
  import type { CsvImportOptions, CsvImportState, ParsedCsv } from "./types.js";
3
+ /** How many rows either adapter's preview step lists. */
4
+ export declare const PREVIEW_ROWS = 50;
5
+ /** What `readAsText` writes for each byte it cannot read as UTF-8. */
6
+ export declare const REPLACEMENT_CHAR = "\uFFFD";
3
7
  export interface CsvImportController {
4
8
  store: MicroStore<CsvImportState>;
5
9
  /** Takes the file the adapter parsed. Does nothing while an import runs. */