@chelone/core 0.5.0 → 0.7.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 (253) hide show
  1. package/dist/assistant/assistant-session.d.ts +28 -0
  2. package/dist/assistant/assistant-session.js +208 -0
  3. package/dist/assistant/echo-transport.d.ts +7 -0
  4. package/dist/assistant/echo-transport.js +28 -0
  5. package/dist/assistant/http-transport.d.ts +10 -0
  6. package/dist/assistant/http-transport.js +98 -0
  7. package/dist/assistant/types.d.ts +54 -0
  8. package/dist/auth/access-control.d.ts +13 -5
  9. package/dist/auth/access-control.js +25 -21
  10. package/dist/auth/auth-options.d.ts +21 -17
  11. package/dist/auth/auth-options.js +80 -48
  12. package/dist/auth/permission-matrix.d.ts +12 -0
  13. package/dist/auth/permission-matrix.js +67 -0
  14. package/dist/auth/types.d.ts +14 -4
  15. package/dist/block-editor/block-document.d.ts +60 -0
  16. package/dist/block-editor/block-document.js +143 -0
  17. package/dist/block-editor/data-blocks.d.ts +63 -0
  18. package/dist/block-editor/data-blocks.js +117 -0
  19. package/dist/chart/chart-data.d.ts +25 -0
  20. package/dist/chart/chart-data.js +61 -0
  21. package/dist/command-menu/hotkey.js +58 -47
  22. package/dist/command-menu/recents.js +8 -11
  23. package/dist/command-menu/registry.d.ts +9 -5
  24. package/dist/command-menu/registry.js +36 -46
  25. package/dist/controller/calendar-dates.js +82 -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 +42 -0
  35. package/dist/controller/in-place-editor.js +42 -0
  36. package/dist/controller/infinite-list-controller.js +220 -190
  37. package/dist/controller/inspector.d.ts +49 -0
  38. package/dist/controller/inspector.js +64 -0
  39. package/dist/controller/job-monitor.d.ts +41 -0
  40. package/dist/controller/job-monitor.js +49 -0
  41. package/dist/controller/kanban-board.d.ts +2 -3
  42. package/dist/controller/kanban-board.js +43 -24
  43. package/dist/controller/list-controller.d.ts +5 -5
  44. package/dist/controller/list-controller.js +444 -400
  45. package/dist/controller/list-params.js +96 -87
  46. package/dist/controller/pivot-grid.d.ts +36 -0
  47. package/dist/controller/pivot-grid.js +99 -0
  48. package/dist/controller/prev-next.d.ts +2 -2
  49. package/dist/controller/prev-next.js +74 -54
  50. package/dist/controller/record-controllers.d.ts +14 -6
  51. package/dist/controller/record-controllers.js +288 -257
  52. package/dist/controller/record-diff.d.ts +21 -0
  53. package/dist/controller/record-diff.js +50 -0
  54. package/dist/controller/record-timeline.d.ts +35 -0
  55. package/dist/controller/record-timeline.js +48 -0
  56. package/dist/controller/record-tree.js +57 -47
  57. package/dist/controller/record-workflow.d.ts +38 -16
  58. package/dist/controller/record-workflow.js +85 -64
  59. package/dist/controller/reference-many-controller.js +198 -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 +2 -1
  65. package/dist/csv/export.js +43 -40
  66. package/dist/csv/import-controller.js +185 -169
  67. package/dist/csv/match-headers.js +29 -22
  68. package/dist/csv/parse-with.js +60 -54
  69. package/dist/csv/run-import.js +69 -72
  70. package/dist/csv/validate-rows.d.ts +1 -1
  71. package/dist/csv/validate-rows.js +65 -52
  72. package/dist/data/cache-ops.d.ts +5 -4
  73. package/dist/data/cache-ops.js +208 -190
  74. package/dist/data/combine-data-providers.js +25 -23
  75. package/dist/data/data-provider-log.d.ts +45 -0
  76. package/dist/data/data-provider-log.js +93 -0
  77. package/dist/data/errors.js +14 -10
  78. package/dist/data/fake-provider.d.ts +6 -3
  79. package/dist/data/fake-provider.js +129 -114
  80. package/dist/data/fetch-utils.js +61 -44
  81. package/dist/data/filter-branch.d.ts +5 -0
  82. package/dist/data/filter-branch.js +10 -0
  83. package/dist/data/get-many-aggregate.js +84 -76
  84. package/dist/data/http-error.js +17 -12
  85. package/dist/data/keys.js +50 -36
  86. package/dist/data/mutation-options.d.ts +14 -9
  87. package/dist/data/mutation-options.js +93 -109
  88. package/dist/data/query-options.js +73 -68
  89. package/dist/data/remove-empty.d.ts +3 -0
  90. package/dist/data/remove-empty.js +11 -0
  91. package/dist/data/undoable.d.ts +2 -2
  92. package/dist/data/undoable.js +190 -174
  93. package/dist/data/with-lifecycle-callbacks.d.ts +45 -17
  94. package/dist/data/with-lifecycle-callbacks.js +66 -52
  95. package/dist/environment/application-update-store.js +58 -55
  96. package/dist/environment/offline-store.js +21 -21
  97. package/dist/form/array-binding.d.ts +30 -11
  98. package/dist/form/array-binding.js +184 -166
  99. package/dist/form/choice-ids.d.ts +7 -0
  100. package/dist/form/choice-ids.js +11 -0
  101. package/dist/form/choices-controller.d.ts +3 -2
  102. package/dist/form/choices-controller.js +302 -275
  103. package/dist/form/date-format.d.ts +38 -0
  104. package/dist/form/date-format.js +89 -0
  105. package/dist/form/dirty-values.d.ts +2 -2
  106. package/dist/form/dirty-values.js +22 -11
  107. package/dist/form/duration.d.ts +22 -0
  108. package/dist/form/duration.js +49 -0
  109. package/dist/form/edit-create-form.d.ts +12 -5
  110. package/dist/form/edit-create-form.js +243 -188
  111. package/dist/form/event-value.d.ts +6 -0
  112. package/dist/form/event-value.js +17 -0
  113. package/dist/form/field-error.d.ts +14 -0
  114. package/dist/form/field-error.js +28 -0
  115. package/dist/form/field-name.d.ts +20 -0
  116. package/dist/form/field-name.js +6 -0
  117. package/dist/form/filter-form-values.js +63 -49
  118. package/dist/form/form-controller.d.ts +9 -1
  119. package/dist/form/form-controller.js +165 -160
  120. package/dist/form/form-groups.d.ts +4 -3
  121. package/dist/form/form-groups.js +79 -79
  122. package/dist/form/form-handle.d.ts +175 -0
  123. package/dist/form/form-handle.js +68 -0
  124. package/dist/form/input-binding.d.ts +56 -31
  125. package/dist/form/input-binding.js +169 -118
  126. package/dist/form/input-values.d.ts +130 -0
  127. package/dist/form/input-values.js +177 -0
  128. package/dist/form/json-text.js +51 -37
  129. package/dist/form/save-pipeline.d.ts +6 -8
  130. package/dist/form/save-pipeline.js +91 -82
  131. package/dist/form/set-form-values.d.ts +6 -0
  132. package/dist/form/set-form-values.js +10 -0
  133. package/dist/form/source.js +97 -65
  134. package/dist/form/text-of.d.ts +2 -0
  135. package/dist/form/text-of.js +7 -0
  136. package/dist/form/validators.d.ts +58 -19
  137. package/dist/form/validators.js +97 -71
  138. package/dist/geo/bbox.d.ts +5 -4
  139. package/dist/geo/bbox.js +69 -48
  140. package/dist/geo/bounds.d.ts +14 -3
  141. package/dist/geo/bounds.js +98 -68
  142. package/dist/geo/constraints.js +88 -93
  143. package/dist/geo/coordinates.js +31 -23
  144. package/dist/geo/editor.d.ts +13 -13
  145. package/dist/geo/editor.js +176 -153
  146. package/dist/geo/geocoding.d.ts +4 -4
  147. package/dist/geo/geocoding.js +38 -41
  148. package/dist/geo/geojson.d.ts +12 -74
  149. package/dist/geo/geojson.js +52 -40
  150. package/dist/geo/geometry-math.d.ts +4 -4
  151. package/dist/geo/geometry-math.js +100 -93
  152. package/dist/geo/index.d.ts +7 -6
  153. package/dist/geo/map-layers.d.ts +42 -7
  154. package/dist/geo/map-layers.js +88 -62
  155. package/dist/geo/map-style.js +31 -32
  156. package/dist/geo/messages.js +48 -45
  157. package/dist/geo/nominatim.js +88 -80
  158. package/dist/geo/osm-presets.d.ts +4 -3
  159. package/dist/geo/osm-presets.js +108 -86
  160. package/dist/geo/osm-tags.js +14 -12
  161. package/dist/geo/overpass.d.ts +14 -2
  162. package/dist/geo/overpass.js +83 -90
  163. package/dist/geo/shape-value.d.ts +9 -5
  164. package/dist/geo/shape-value.js +169 -146
  165. package/dist/geo/snap-to-roads.d.ts +3 -3
  166. package/dist/geo/snap-to-roads.js +55 -50
  167. package/dist/geo/throttle.js +36 -39
  168. package/dist/guards.d.ts +37 -0
  169. package/dist/guards.js +62 -0
  170. package/dist/i18n/default-messages.js +34 -29
  171. package/dist/i18n/english-messages.js +187 -189
  172. package/dist/i18n/i18n.d.ts +8 -2
  173. package/dist/i18n/i18n.js +47 -48
  174. package/dist/i18n/inflection.d.ts +34 -0
  175. package/dist/i18n/inflection.js +82 -0
  176. package/dist/i18n/messages.d.ts +10 -2
  177. package/dist/i18n/messages.js +17 -4
  178. package/dist/i18n/missing-keys.d.ts +19 -0
  179. package/dist/i18n/missing-keys.js +68 -0
  180. package/dist/i18n/translatable.d.ts +16 -1
  181. package/dist/i18n/translatable.js +40 -47
  182. package/dist/index.d.ts +96 -22
  183. package/dist/index.js +52 -257
  184. package/dist/json/deep-equal.d.ts +8 -0
  185. package/dist/json/deep-equal.js +24 -0
  186. package/dist/json/strip-json-comments.js +38 -42
  187. package/dist/noop.d.ts +2 -0
  188. package/dist/noop.js +4 -0
  189. package/dist/notification/error-message.d.ts +2 -0
  190. package/dist/notification/error-message.js +10 -0
  191. package/dist/notification/notification-store.d.ts +3 -2
  192. package/dist/notification/notification-store.js +41 -45
  193. package/dist/onboarding-tour/placement.d.ts +34 -0
  194. package/dist/onboarding-tour/placement.js +67 -0
  195. package/dist/onboarding-tour/tour-controller.d.ts +25 -0
  196. package/dist/onboarding-tour/tour-controller.js +50 -0
  197. package/dist/realtime/add-events-for-mutations.js +75 -81
  198. package/dist/realtime/announce-lock.d.ts +7 -0
  199. package/dist/realtime/announce-lock.js +18 -0
  200. package/dist/realtime/broadcast-channel-transport.d.ts +14 -0
  201. package/dist/realtime/broadcast-channel-transport.js +69 -0
  202. package/dist/realtime/copy-members.js +22 -14
  203. package/dist/realtime/in-memory-lock-provider.js +41 -60
  204. package/dist/realtime/live.js +95 -101
  205. package/dist/realtime/lock-options.js +16 -16
  206. package/dist/realtime/lock-session.js +91 -78
  207. package/dist/realtime/memory-transport.js +26 -67
  208. package/dist/realtime/presence.js +120 -122
  209. package/dist/realtime/realtime-data-provider.d.ts +10 -0
  210. package/dist/realtime/realtime-data-provider.js +45 -42
  211. package/dist/realtime/reconnect-backoff.d.ts +15 -0
  212. package/dist/realtime/reconnect-backoff.js +17 -0
  213. package/dist/realtime/sse-transport.d.ts +31 -0
  214. package/dist/realtime/sse-transport.js +235 -0
  215. package/dist/realtime/status-store.js +23 -28
  216. package/dist/realtime/topic-hub.d.ts +24 -0
  217. package/dist/realtime/topic-hub.js +66 -0
  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 +232 -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 +16 -1
  236. package/dist/rich-text/rich-text-extras.d.ts +132 -0
  237. package/dist/rich-text/rich-text-extras.js +179 -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 +62 -0
  241. package/dist/rich-text/rich-text.js +142 -0
  242. package/dist/router/location.d.ts +22 -4
  243. package/dist/router/location.js +41 -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/package.json +13 -11
@@ -0,0 +1,61 @@
1
+ // src/chart/chart-data.ts
2
+ /** Theme variables the registry ships, in series order. */
3
+ var DEFAULT_CHART_COLORS = [
4
+ "var(--chart-1)",
5
+ "var(--chart-2)",
6
+ "var(--chart-3)",
7
+ "var(--chart-4)",
8
+ "var(--chart-5)"
9
+ ];
10
+ var FALLBACK_COLOR = "var(--chart-1)";
11
+ function chartColor(index, colors = DEFAULT_CHART_COLORS) {
12
+ const list = colors.length > 0 ? colors : DEFAULT_CHART_COLORS;
13
+ const length = list.length;
14
+ return list[(index % length + length) % length] ?? FALLBACK_COLOR;
15
+ }
16
+ function toFiniteNumber(value) {
17
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
18
+ if (typeof value === "string" && value.trim() !== "") {
19
+ const parsed = Number(value);
20
+ return Number.isFinite(parsed) ? parsed : null;
21
+ }
22
+ return null;
23
+ }
24
+ function toCartesianRows(data, xField, yField) {
25
+ return data.map((row, index) => ({
26
+ index,
27
+ x: row[xField],
28
+ y: toFiniteNumber(row[yField])
29
+ }));
30
+ }
31
+ function hasChartValues(rows) {
32
+ return rows.some((row) => row.y !== null);
33
+ }
34
+ function toLabel(value) {
35
+ return value === void 0 || value === null ? "" : String(value);
36
+ }
37
+ function toDonutSlices(data, labelField, valueField) {
38
+ const kept = [];
39
+ for (const row of data) {
40
+ const value = toFiniteNumber(row[valueField]);
41
+ if (value !== null && value > 0) kept.push({
42
+ label: toLabel(row[labelField]),
43
+ value
44
+ });
45
+ }
46
+ const total = kept.reduce((sum, slice) => sum + slice.value, 0);
47
+ if (total <= 0) return [];
48
+ return kept.map((slice) => ({
49
+ ...slice,
50
+ share: slice.value / total
51
+ }));
52
+ }
53
+ /** `delta` is a ratio (0.05 is 5.0%). Direction follows the sign of `delta`, not of the rounded text. */
54
+ function getMetricDelta(delta) {
55
+ if (delta === void 0 || !Number.isFinite(delta)) return null;
56
+ return {
57
+ direction: delta > 0 ? "up" : delta < 0 ? "down" : "flat",
58
+ text: `${(delta * 100).toFixed(1)}%`
59
+ };
60
+ }
61
+ export { DEFAULT_CHART_COLORS, chartColor, getMetricDelta, hasChartValues, toCartesianRows, toDonutSlices };
@@ -1,60 +1,71 @@
1
+ // src/command-menu/hotkey.ts
1
2
  function parseBinding(binding) {
2
- const lower = binding.toLowerCase();
3
- const plus = lower === "+" || lower.endsWith("++");
4
- const parts = (plus ? lower.slice(0, -1) : lower).split("+");
5
- const key = plus ? "+" : parts.pop() ?? "";
6
- return {
7
- key,
8
- mod: parts.includes("mod"),
9
- shift: parts.includes("shift"),
10
- alt: parts.includes("alt")
11
- };
3
+ const lower = binding.toLowerCase();
4
+ const plus = lower === "+" || lower.endsWith("++");
5
+ const parts = (plus ? lower.slice(0, -1) : lower).split("+");
6
+ return {
7
+ key: plus ? "+" : parts.pop() ?? "",
8
+ mod: parts.includes("mod"),
9
+ shift: parts.includes("shift"),
10
+ alt: parts.includes("alt")
11
+ };
12
12
  }
13
- const punctuationCodes = {
14
- "/": "Slash",
15
- ".": "Period",
16
- ",": "Comma",
17
- ";": "Semicolon",
18
- "'": "Quote",
19
- "[": "BracketLeft",
20
- "]": "BracketRight",
21
- "\\": "Backslash",
22
- "-": "Minus",
23
- "=": "Equal",
24
- "`": "Backquote"
13
+ var punctuationCodes = {
14
+ "/": "Slash",
15
+ ".": "Period",
16
+ ",": "Comma",
17
+ ";": "Semicolon",
18
+ "'": "Quote",
19
+ "[": "BracketLeft",
20
+ "]": "BracketRight",
21
+ "\\": "Backslash",
22
+ "-": "Minus",
23
+ "=": "Equal",
24
+ "`": "Backquote"
25
25
  };
26
26
  function codeFor(key) {
27
- if (/^[a-z]$/.test(key)) return `Key${key.toUpperCase()}`;
28
- if (/^[0-9]$/.test(key)) return `Digit${key}`;
29
- return punctuationCodes[key];
27
+ if (/^[a-z]$/.test(key)) return `Key${key.toUpperCase()}`;
28
+ if (/^[0-9]$/.test(key)) return `Digit${key}`;
29
+ return punctuationCodes[key];
30
30
  }
31
+ /**
32
+ * Option and Shift rewrite `event.key` ("÷" for Option+/, "!" for Shift+1), so
33
+ * a chord with either falls back to the physical key, but only when `key` is
34
+ * not already a letter or digit. On a Dvorak layout the physical K key types
35
+ * "t": that stays a "t", so `mod+k` does not fire on it.
36
+ */
31
37
  function keyMatches(event, parsed, eventKey) {
32
- if (eventKey === parsed.key) return true;
33
- if (!(parsed.alt || parsed.shift) || !event.code) return false;
34
- if (/^[a-z0-9]$/i.test(event.key)) return false;
35
- return event.code === codeFor(parsed.key);
38
+ if (eventKey === parsed.key) return true;
39
+ if (!(parsed.alt || parsed.shift) || !event.code) return false;
40
+ if (/^[a-z0-9]$/i.test(event.key)) return false;
41
+ return event.code === codeFor(parsed.key);
36
42
  }
43
+ /**
44
+ * Reads bindings such as `"mod+k"`, `"mod+shift+p"`, `"alt+/"` and `"f1"`.
45
+ * `mod` is Meta or Ctrl. Modifiers match exactly: a binding without `mod`
46
+ * does not fire while Ctrl or Meta is down.
47
+ */
37
48
  function matchesHotkey(event, binding) {
38
- const parsed = parseBinding(binding);
39
- if (!keyMatches(event, parsed, event.key.toLowerCase())) return false;
40
- const modDown = event.metaKey || event.ctrlKey;
41
- return modDown === parsed.mod && event.shiftKey === parsed.shift && event.altKey === parsed.alt;
49
+ const parsed = parseBinding(binding);
50
+ if (!keyMatches(event, parsed, event.key.toLowerCase())) return false;
51
+ return (event.metaKey || event.ctrlKey) === parsed.mod && event.shiftKey === parsed.shift && event.altKey === parsed.alt;
42
52
  }
43
53
  function isTypingTarget(target) {
44
- if (!target) return false;
45
- if (target.isContentEditable) return true;
46
- const tag = target.tagName?.toLowerCase();
47
- return tag === "input" || tag === "textarea" || tag === "select";
54
+ if (!target) return false;
55
+ if (target.isContentEditable) return true;
56
+ const tag = target.tagName?.toLowerCase();
57
+ return tag === "input" || tag === "textarea" || tag === "select";
48
58
  }
59
+ /**
60
+ * `matchesHotkey` plus two guards: nothing fires during IME composition, and a
61
+ * binding with neither `mod` nor `alt` is ignored while `target` is typing, so
62
+ * `/` never opens the menu from a text field.
63
+ */
49
64
  function shouldHandleHotkey(event, binding, target) {
50
- if (event.isComposing) return false;
51
- if (!matchesHotkey(event, binding)) return false;
52
- const { mod, alt } = parseBinding(binding);
53
- if (!mod && !alt && isTypingTarget(target)) return false;
54
- return true;
65
+ if (event.isComposing) return false;
66
+ if (!matchesHotkey(event, binding)) return false;
67
+ const { mod, alt } = parseBinding(binding);
68
+ if (!mod && !alt && isTypingTarget(target)) return false;
69
+ return true;
55
70
  }
56
- export {
57
- isTypingTarget,
58
- matchesHotkey,
59
- shouldHandleHotkey
60
- };
71
+ export { isTypingTarget, matchesHotkey, shouldHandleHotkey };
@@ -1,15 +1,12 @@
1
- const recentsKey = "command-menu.recents";
1
+ // src/command-menu/recents.ts
2
+ /** Where the command menu keeps its recents in a `CheloneStore`. */
3
+ var recentsKey = "command-menu.recents";
2
4
  function sameEntry(a, b) {
3
- return a.type === b.type && a.resource === b.resource && (a.id === void 0 ? void 0 : String(a.id)) === (b.id === void 0 ? void 0 : String(b.id));
5
+ return a.type === b.type && a.resource === b.resource && (a.id === void 0 ? void 0 : String(a.id)) === (b.id === void 0 ? void 0 : String(b.id));
4
6
  }
7
+ /** Puts `entry` first, drops an earlier copy, and cuts to `limit`. */
5
8
  function rememberRecent(recents, entry, limit) {
6
- if (limit < 1) return [];
7
- return [entry, ...recents.filter((other) => !sameEntry(other, entry))].slice(
8
- 0,
9
- limit
10
- );
9
+ if (limit < 1) return [];
10
+ return [entry, ...recents.filter((other) => !sameEntry(other, entry))].slice(0, limit);
11
11
  }
12
- export {
13
- recentsKey,
14
- rememberRecent
15
- };
12
+ export { recentsKey, rememberRecent };
@@ -3,7 +3,7 @@ import { type MicroStore } from "../store/micro-store.js";
3
3
  * An extra command in the menu. `label` and `icon` are generic so each adapter
4
4
  * uses its own types (a React node, a Vue component).
5
5
  */
6
- export interface CommandAction<TLabel = string, TIcon = unknown> {
6
+ export interface CommandAction<TLabel, TIcon> {
7
7
  id: string;
8
8
  label: TLabel;
9
9
  icon?: TIcon;
@@ -15,7 +15,7 @@ export interface CommandAction<TLabel = string, TIcon = unknown> {
15
15
  when?: () => boolean;
16
16
  onSelect: () => void;
17
17
  }
18
- export interface CommandRegistry<TLabel = string, TIcon = unknown> {
18
+ export interface CommandRegistry<TLabel, TIcon> {
19
19
  store: MicroStore<{
20
20
  commands: CommandAction<TLabel, TIcon>[];
21
21
  }>;
@@ -28,7 +28,11 @@ export interface CommandRegistry<TLabel = string, TIcon = unknown> {
28
28
  unregister(id: string): void;
29
29
  }
30
30
  export declare const defaultCommandGroup = "actions";
31
- export declare function createCommandRegistry<TLabel = string, TIcon = unknown>(): CommandRegistry<TLabel, TIcon>;
32
- export declare function getVisibleCommands<T extends Pick<CommandAction, "when">>(commands: readonly T[]): T[];
31
+ export declare function createCommandRegistry<TLabel, TIcon>(): CommandRegistry<TLabel, TIcon>;
32
+ export declare function getVisibleCommands<T extends {
33
+ when?: () => boolean;
34
+ }>(commands: readonly T[]): T[];
33
35
  /** Groups in first-seen order. A missing `group` reads as `"actions"`. */
34
- export declare function groupCommands<T extends Pick<CommandAction, "group">>(commands: readonly T[]): [string, T[]][];
36
+ export declare function groupCommands<T extends {
37
+ group?: string;
38
+ }>(commands: readonly T[]): [string, T[]][];
@@ -1,53 +1,43 @@
1
1
  import { createMicroStore } from "../store/micro-store.js";
2
- const defaultCommandGroup = "actions";
2
+ // src/command-menu/registry.ts
3
+ var defaultCommandGroup = "actions";
3
4
  function createCommandRegistry() {
4
- const store = createMicroStore({
5
- commands: []
6
- });
7
- const unregister = (id) => {
8
- store.setState((prev) => ({
9
- commands: prev.commands.filter((command) => command.id !== id)
10
- }));
11
- };
12
- const register = (action) => {
13
- store.setState((prev) => {
14
- const exists = prev.commands.some((command) => command.id === action.id);
15
- return {
16
- commands: exists ? prev.commands.map(
17
- (command) => command.id === action.id ? action : command
18
- ) : [...prev.commands, action]
19
- };
20
- });
21
- return () => {
22
- store.setState((prev) => ({
23
- commands: prev.commands.filter((command) => command !== action)
24
- }));
25
- };
26
- };
27
- return { store, register, unregister };
5
+ const store = createMicroStore({ commands: [] });
6
+ const unregister = (id) => {
7
+ store.setState((prev) => ({ commands: prev.commands.filter((command) => command.id !== id) }));
8
+ };
9
+ const register = (action) => {
10
+ store.setState((prev) => {
11
+ return { commands: prev.commands.some((command) => command.id === action.id) ? prev.commands.map((command) => command.id === action.id ? action : command) : [...prev.commands, action] };
12
+ });
13
+ return () => {
14
+ store.setState((prev) => ({ commands: prev.commands.filter((command) => command !== action) }));
15
+ };
16
+ };
17
+ return {
18
+ store,
19
+ register,
20
+ unregister
21
+ };
28
22
  }
29
23
  function getVisibleCommands(commands) {
30
- return commands.filter((command) => {
31
- try {
32
- return command.when ? command.when() !== false : true;
33
- } catch {
34
- return false;
35
- }
36
- });
24
+ return commands.filter((command) => {
25
+ try {
26
+ return command.when ? command.when() !== false : true;
27
+ } catch {
28
+ return false;
29
+ }
30
+ });
37
31
  }
32
+ /** Groups in first-seen order. A missing `group` reads as `"actions"`. */
38
33
  function groupCommands(commands) {
39
- const groups = /* @__PURE__ */ new Map();
40
- for (const command of commands) {
41
- const group = command.group ?? defaultCommandGroup;
42
- const members = groups.get(group);
43
- if (members) members.push(command);
44
- else groups.set(group, [command]);
45
- }
46
- return [...groups];
34
+ const groups = /* @__PURE__ */ new Map();
35
+ for (const command of commands) {
36
+ const group = command.group ?? "actions";
37
+ const members = groups.get(group);
38
+ if (members) members.push(command);
39
+ else groups.set(group, [command]);
40
+ }
41
+ return [...groups];
47
42
  }
48
- export {
49
- createCommandRegistry,
50
- defaultCommandGroup,
51
- getVisibleCommands,
52
- groupCommands
53
- };
43
+ export { createCommandRegistry, defaultCommandGroup, getVisibleCommands, groupCommands };
@@ -1,123 +1,92 @@
1
- const DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
2
- const AGENDA_DAYS = 14;
3
- const atMidnight = (date, dayOffset = 0) => new Date(date.getFullYear(), date.getMonth(), date.getDate() + dayOffset);
4
- const atEndOfDay = (date, dayOffset = 0) => new Date(
5
- date.getFullYear(),
6
- date.getMonth(),
7
- date.getDate() + dayOffset,
8
- 23,
9
- 59,
10
- 59,
11
- 999
12
- );
13
- const daysFromWeekStart = (date, weekStartsOn) => (date.getDay() - weekStartsOn + 7) % 7;
1
+ // src/controller/calendar-dates.ts
2
+ var DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
3
+ var AGENDA_DAYS = 14;
4
+ var atMidnight = (date, dayOffset = 0) => new Date(date.getFullYear(), date.getMonth(), date.getDate() + dayOffset);
5
+ var atEndOfDay = (date, dayOffset = 0) => new Date(date.getFullYear(), date.getMonth(), date.getDate() + dayOffset, 23, 59, 59, 999);
6
+ var daysFromWeekStart = (date, weekStartsOn) => (date.getDay() - weekStartsOn + 7) % 7;
7
+ /**
8
+ * A date-only string is local midnight: `new Date("2026-05-01")` reads it as
9
+ * UTC, which is the previous day west of Greenwich.
10
+ */
14
11
  function parseCalendarDate(value) {
15
- let date;
16
- if (value instanceof Date) {
17
- date = new Date(value.getTime());
18
- } else if (typeof value === "number") {
19
- date = new Date(value);
20
- } else if (typeof value === "string") {
21
- const dateOnly = DATE_ONLY.exec(value);
22
- if (dateOnly) {
23
- const [year, month, day] = [
24
- Number(dateOnly[1]),
25
- Number(dateOnly[2]),
26
- Number(dateOnly[3])
27
- ];
28
- date = new Date(2e3, 0, 1);
29
- date.setFullYear(year, month - 1, day);
30
- if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
31
- return void 0;
32
- }
33
- } else {
34
- date = new Date(value);
35
- }
36
- } else {
37
- return void 0;
38
- }
39
- return Number.isNaN(date.getTime()) ? void 0 : date;
12
+ let date;
13
+ if (value instanceof Date) date = new Date(value.getTime());
14
+ else if (typeof value === "number") date = new Date(value);
15
+ else if (typeof value === "string") {
16
+ const dateOnly = DATE_ONLY.exec(value);
17
+ if (dateOnly) {
18
+ const [year, month, day] = [
19
+ Number(dateOnly[1]),
20
+ Number(dateOnly[2]),
21
+ Number(dateOnly[3])
22
+ ];
23
+ date = new Date(2e3, 0, 1);
24
+ date.setFullYear(year, month - 1, day);
25
+ if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) return;
26
+ } else date = new Date(value);
27
+ } else return;
28
+ return Number.isNaN(date.getTime()) ? void 0 : date;
40
29
  }
41
30
  function calendarRange(view, anchor, weekStartsOn) {
42
- if (view === "agenda") {
43
- return {
44
- start: atMidnight(anchor, -AGENDA_DAYS),
45
- end: atEndOfDay(anchor, AGENDA_DAYS)
46
- };
47
- }
48
- const first = view === "month" ? new Date(anchor.getFullYear(), anchor.getMonth(), 1) : anchor;
49
- const last = view === "month" ? new Date(anchor.getFullYear(), anchor.getMonth() + 1, 0) : anchor;
50
- return {
51
- start: atMidnight(first, -daysFromWeekStart(first, weekStartsOn)),
52
- end: atEndOfDay(last, 6 - daysFromWeekStart(last, weekStartsOn))
53
- };
31
+ if (view === "agenda") return {
32
+ start: atMidnight(anchor, -14),
33
+ end: atEndOfDay(anchor, AGENDA_DAYS)
34
+ };
35
+ const first = view === "month" ? new Date(anchor.getFullYear(), anchor.getMonth(), 1) : anchor;
36
+ const last = view === "month" ? new Date(anchor.getFullYear(), anchor.getMonth() + 1, 0) : anchor;
37
+ return {
38
+ start: atMidnight(first, -daysFromWeekStart(first, weekStartsOn)),
39
+ end: atEndOfDay(last, 6 - daysFromWeekStart(last, weekStartsOn))
40
+ };
54
41
  }
42
+ /** One local midnight per day: adding to the day of the month never skips or repeats a day when the clocks change. */
55
43
  function calendarDays(range) {
56
- const days = [];
57
- const first = atMidnight(range.start);
58
- for (let day = first; day.getTime() <= range.end.getTime(); day = atMidnight(first, days.length)) {
59
- days.push(day);
60
- }
61
- return days;
44
+ const days = [];
45
+ const first = atMidnight(range.start);
46
+ for (let day = first; day.getTime() <= range.end.getTime(); day = atMidnight(first, days.length)) days.push(day);
47
+ return days;
62
48
  }
63
49
  function shiftCalendarAnchor(view, anchor, direction) {
64
- const time = [
65
- anchor.getHours(),
66
- anchor.getMinutes(),
67
- anchor.getSeconds(),
68
- anchor.getMilliseconds()
69
- ];
70
- if (view === "month") {
71
- const month = anchor.getMonth() + direction;
72
- const lastDay = new Date(anchor.getFullYear(), month + 1, 0).getDate();
73
- return new Date(
74
- anchor.getFullYear(),
75
- month,
76
- Math.min(anchor.getDate(), lastDay),
77
- ...time
78
- );
79
- }
80
- const step = view === "week" ? 7 : AGENDA_DAYS;
81
- return new Date(
82
- anchor.getFullYear(),
83
- anchor.getMonth(),
84
- anchor.getDate() + direction * step,
85
- ...time
86
- );
50
+ const time = [
51
+ anchor.getHours(),
52
+ anchor.getMinutes(),
53
+ anchor.getSeconds(),
54
+ anchor.getMilliseconds()
55
+ ];
56
+ if (view === "month") {
57
+ const month = anchor.getMonth() + direction;
58
+ const lastDay = new Date(anchor.getFullYear(), month + 1, 0).getDate();
59
+ return new Date(anchor.getFullYear(), month, Math.min(anchor.getDate(), lastDay), ...time);
60
+ }
61
+ const step = view === "week" ? 7 : AGENDA_DAYS;
62
+ return new Date(anchor.getFullYear(), anchor.getMonth(), anchor.getDate() + direction * step, ...time);
87
63
  }
88
- const pad = (value) => String(value).padStart(2, "0");
89
- const calendarDayKey = (date) => `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
64
+ var pad = (value) => String(value).padStart(2, "0");
65
+ var calendarDayKey = (date) => `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
90
66
  function calendarLabels(locale) {
91
- const month = new Intl.DateTimeFormat(locale, {
92
- month: "long",
93
- year: "numeric"
94
- });
95
- const span = new Intl.DateTimeFormat(locale, {
96
- month: "short",
97
- day: "numeric",
98
- year: "numeric"
99
- });
100
- const weekday = new Intl.DateTimeFormat(locale, { weekday: "short" });
101
- const dayNumber = new Intl.DateTimeFormat(locale, { day: "numeric" });
102
- const hour = new Intl.DateTimeFormat(locale, { hour: "numeric" });
103
- const agendaDay = new Intl.DateTimeFormat(locale, {
104
- weekday: "long",
105
- month: "long",
106
- day: "numeric"
107
- });
108
- return {
109
- title: (view, anchor, range) => view === "month" ? month.format(anchor) : span.formatRange(range.start, range.end),
110
- weekday: (date) => weekday.format(date),
111
- dayNumber: (date) => dayNumber.format(date),
112
- hour: (value) => hour.format(new Date(2e3, 0, 1, value)),
113
- agendaDay: (date) => agendaDay.format(date)
114
- };
67
+ const month = new Intl.DateTimeFormat(locale, {
68
+ month: "long",
69
+ year: "numeric"
70
+ });
71
+ const span = new Intl.DateTimeFormat(locale, {
72
+ month: "short",
73
+ day: "numeric",
74
+ year: "numeric"
75
+ });
76
+ const weekday = new Intl.DateTimeFormat(locale, { weekday: "short" });
77
+ const dayNumber = new Intl.DateTimeFormat(locale, { day: "numeric" });
78
+ const hour = new Intl.DateTimeFormat(locale, { hour: "numeric" });
79
+ const agendaDay = new Intl.DateTimeFormat(locale, {
80
+ weekday: "long",
81
+ month: "long",
82
+ day: "numeric"
83
+ });
84
+ return {
85
+ title: (view, anchor, range) => view === "month" ? month.format(anchor) : span.formatRange(range.start, range.end),
86
+ weekday: (date) => weekday.format(date),
87
+ dayNumber: (date) => dayNumber.format(date),
88
+ hour: (value) => hour.format(new Date(2e3, 0, 1, value)),
89
+ agendaDay: (date) => agendaDay.format(date)
90
+ };
115
91
  }
116
- export {
117
- calendarDayKey,
118
- calendarDays,
119
- calendarLabels,
120
- calendarRange,
121
- parseCalendarDate,
122
- shiftCalendarAnchor
123
- };
92
+ export { calendarDayKey, calendarDays, calendarLabels, calendarRange, parseCalendarDate, shiftCalendarAnchor };