@joewinke/jatui 0.38.6 → 0.39.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 (62) hide show
  1. package/CLAUDE.md +31 -0
  2. package/THIRD_PARTY_NOTICES.md +51 -0
  3. package/dist/components/BulkActionBar.svelte +32 -2
  4. package/dist/components/BulkActionBar.svelte.d.ts +5 -1
  5. package/dist/components/FloatingActionBar.svelte +102 -34
  6. package/dist/components/FloatingActionBar.svelte.d.ts +9 -0
  7. package/dist/components/MediaExplorer.svelte +249 -0
  8. package/dist/components/MediaExplorer.svelte.d.ts +37 -0
  9. package/dist/components/NotificationCenter.svelte +481 -0
  10. package/dist/components/NotificationCenter.svelte.d.ts +29 -0
  11. package/dist/components/SearchDropdown.svelte +54 -8
  12. package/dist/components/SearchDropdown.svelte.d.ts +12 -0
  13. package/dist/components/agent/AgentLog.svelte +217 -0
  14. package/dist/components/agent/AgentLog.svelte.d.ts +72 -0
  15. package/dist/components/agent/AgentLogRow.svelte +281 -0
  16. package/dist/components/agent/AgentLogRow.svelte.d.ts +21 -0
  17. package/dist/components/agent/AgentTaskList.svelte +607 -0
  18. package/dist/components/agent/AgentTaskList.svelte.d.ts +40 -0
  19. package/dist/components/agent/AgentThinking.svelte +280 -0
  20. package/dist/components/agent/AgentThinking.svelte.d.ts +22 -0
  21. package/dist/components/agent/ComposerGlow.svelte +265 -0
  22. package/dist/components/agent/ComposerGlow.svelte.d.ts +18 -0
  23. package/dist/components/agent/ContextMeter.svelte +277 -0
  24. package/dist/components/agent/ContextMeter.svelte.d.ts +21 -0
  25. package/dist/components/agent/Questionnaire.svelte +767 -0
  26. package/dist/components/agent/Questionnaire.svelte.d.ts +29 -0
  27. package/dist/components/agent/ShimmerText.svelte +100 -0
  28. package/dist/components/agent/ShimmerText.svelte.d.ts +19 -0
  29. package/dist/components/agent/StreamedText.svelte +135 -0
  30. package/dist/components/agent/StreamedText.svelte.d.ts +13 -0
  31. package/dist/components/agent/agentLog.d.ts +22 -0
  32. package/dist/components/agent/agentLog.js +26 -0
  33. package/dist/components/agent/agentTaskList.d.ts +90 -0
  34. package/dist/components/agent/agentTaskList.js +93 -0
  35. package/dist/components/agent/agentThinking.d.ts +46 -0
  36. package/dist/components/agent/agentThinking.js +78 -0
  37. package/dist/components/agent/contextMeter.d.ts +97 -0
  38. package/dist/components/agent/contextMeter.js +156 -0
  39. package/dist/components/agent/questionnaire.d.ts +104 -0
  40. package/dist/components/agent/questionnaire.js +225 -0
  41. package/dist/components/agent/revealCore.d.ts +74 -0
  42. package/dist/components/agent/revealCore.js +160 -0
  43. package/dist/components/agent/revealTicker.d.ts +34 -0
  44. package/dist/components/agent/revealTicker.js +73 -0
  45. package/dist/components/agent/streamedText.d.ts +28 -0
  46. package/dist/components/agent/streamedText.js +59 -0
  47. package/dist/components/messaging/MessageInput.svelte +34 -4
  48. package/dist/components/messaging/MessageInput.svelte.d.ts +7 -0
  49. package/dist/components/messaging/MessageItem.svelte +2 -2
  50. package/dist/components/notificationCenter.d.ts +65 -0
  51. package/dist/components/notificationCenter.js +110 -0
  52. package/dist/components/progress/Steps.svelte +269 -5
  53. package/dist/components/progress/Steps.svelte.d.ts +16 -1
  54. package/dist/components/progress/stepsSummary.d.ts +14 -0
  55. package/dist/components/progress/stepsSummary.js +32 -0
  56. package/dist/index.d.ts +34 -0
  57. package/dist/index.js +29 -0
  58. package/dist/selection/clickSelection.d.ts +89 -0
  59. package/dist/selection/clickSelection.js +152 -0
  60. package/dist/selection/createClickSelection.d.ts +79 -0
  61. package/dist/selection/createClickSelection.js +134 -0
  62. package/package.json +3 -2
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Pointer-first multi-selection: the desktop-standard click rules, as pure
3
+ * functions over a plain `Set` (a `SvelteSet` is a `Set`, so the reactive
4
+ * controller in `createClickSelection.svelte.ts` runs exactly this code).
5
+ *
6
+ * click select only this one; it becomes the anchor
7
+ * Ctrl/⌘ click toggle this one; it becomes the anchor
8
+ * Shift click select the range anchor..this, in the current id order
9
+ * (replaces the selection; the anchor stays put)
10
+ * Shift Ctrl/⌘ add the range anchor..this to the selection
11
+ * Shift arrows extend from the anchor (the caller says which id an
12
+ * arrow lands on, because only it knows the layout)
13
+ * Ctrl/⌘ A select every id
14
+ * Esc clear
15
+ *
16
+ * The selection is a set of ids, not of positions: re-sorting, filtering or
17
+ * live inserts keep it, and an id that is no longer in `ids` is simply not
18
+ * selected any more (`prune` drops it, the readers filter it out first).
19
+ *
20
+ * `head` is the moving end of the last range (the last id clicked or
21
+ * extended to), so Shift+arrows keep growing from where they left off.
22
+ *
23
+ * No DOM, no Svelte: unit-tested in tests/unit/clickSelection.test.ts.
24
+ */
25
+ import { isTypingTarget } from '../utils/keyboardShortcutRegistry';
26
+ /** Ctrl on Linux/Windows, ⌘ on macOS: either counts as "toggle / add". */
27
+ export const isAdditive = (m) => !!(m.ctrlKey || m.metaKey);
28
+ /** The ids from `a` to `b` inclusive, in `ids` order (either direction). Empty when either is missing. */
29
+ export function rangeBetween(ids, a, b) {
30
+ const i = ids.indexOf(a);
31
+ const j = ids.indexOf(b);
32
+ if (i < 0 || j < 0)
33
+ return [];
34
+ return i <= j ? ids.slice(i, j + 1) : ids.slice(j, i + 1);
35
+ }
36
+ /** Select only `id` and make it the anchor (a plain click, or a plain arrow move). */
37
+ export function selectOnly(s, id) {
38
+ s.selected.clear();
39
+ s.selected.add(id);
40
+ s.anchor = id;
41
+ s.head = id;
42
+ }
43
+ /** Toggle `id` and make it the anchor (Ctrl/⌘ click). */
44
+ export function toggleOne(s, id) {
45
+ if (s.selected.has(id))
46
+ s.selected.delete(id);
47
+ else
48
+ s.selected.add(id);
49
+ s.anchor = id;
50
+ s.head = id;
51
+ }
52
+ /**
53
+ * Select the range from the anchor to `id` (Shift click / Shift arrows).
54
+ * `additive` keeps what was selected and adds the range (Shift+Ctrl/⌘).
55
+ * With no usable anchor (none yet, or it vanished) it behaves as a plain
56
+ * click on `id` (or a toggle-on when additive).
57
+ */
58
+ export function extendTo(s, ids, id, additive = false) {
59
+ if (!ids.includes(id))
60
+ return;
61
+ const anchor = s.anchor !== null && ids.includes(s.anchor) ? s.anchor : null;
62
+ if (anchor === null) {
63
+ if (additive) {
64
+ s.selected.add(id);
65
+ s.anchor = id;
66
+ s.head = id;
67
+ }
68
+ else
69
+ selectOnly(s, id);
70
+ return;
71
+ }
72
+ const range = rangeBetween(ids, anchor, id);
73
+ if (!additive)
74
+ s.selected.clear();
75
+ for (const x of range)
76
+ s.selected.add(x);
77
+ s.head = id;
78
+ }
79
+ /** Apply one click on `id` with its modifiers. Ids not in `ids` are ignored. */
80
+ export function applyClick(s, ids, id, m = {}) {
81
+ if (!ids.includes(id))
82
+ return;
83
+ prune(s, ids);
84
+ if (m.shiftKey)
85
+ return extendTo(s, ids, id, isAdditive(m));
86
+ if (isAdditive(m))
87
+ return toggleOne(s, id);
88
+ selectOnly(s, id);
89
+ }
90
+ /** Select every id (Ctrl/⌘ A). The anchor stays if it is still there, else the first id. */
91
+ export function selectAll(s, ids) {
92
+ s.selected.clear();
93
+ for (const x of ids)
94
+ s.selected.add(x);
95
+ if (s.anchor === null || !ids.includes(s.anchor))
96
+ s.anchor = ids[0] ?? null;
97
+ s.head = ids.at(-1) ?? null;
98
+ }
99
+ /** Clear the selection and the range ends (Esc). */
100
+ export function clearSelection(s) {
101
+ s.selected.clear();
102
+ s.anchor = null;
103
+ s.head = null;
104
+ }
105
+ /** Drop selected ids that are no longer in `ids` (and an anchor or head that vanished). True when anything changed. */
106
+ export function prune(s, ids) {
107
+ const present = new Set(ids);
108
+ let changed = false;
109
+ for (const x of [...s.selected]) {
110
+ if (!present.has(x)) {
111
+ s.selected.delete(x);
112
+ changed = true;
113
+ }
114
+ }
115
+ if (s.anchor !== null && !present.has(s.anchor)) {
116
+ s.anchor = null;
117
+ changed = true;
118
+ }
119
+ if (s.head !== null && !present.has(s.head)) {
120
+ s.head = null;
121
+ changed = true;
122
+ }
123
+ return changed;
124
+ }
125
+ /** The selected ids that are still present, in `ids` order (what a range or a list shows). */
126
+ export const inOrder = (selected, ids) => ids.filter((x) => selected.has(x));
127
+ /** The selected ids that are still present, in the order they were selected (Set insertion order). */
128
+ export function inPickOrder(selected, ids) {
129
+ const present = new Set(ids);
130
+ return [...selected].filter((x) => present.has(x));
131
+ }
132
+ export const ARROW_KEYS = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
133
+ /**
134
+ * Which selection key this is, if any: Ctrl/⌘ A (select all), Esc (clear,
135
+ * only while something is selected, so Esc keeps its other meanings when
136
+ * nothing is), Shift+arrows (extend; with Ctrl/⌘ too, add the range).
137
+ * Never while typing in a field, never with Alt, never when already handled.
138
+ */
139
+ export function selectionKey(e, hasSelection) {
140
+ if (e.defaultPrevented || e.altKey)
141
+ return null;
142
+ if (isTypingTarget(e.target ?? null))
143
+ return null;
144
+ const mod = isAdditive(e);
145
+ if (mod && !e.shiftKey && (e.key === 'a' || e.key === 'A'))
146
+ return { kind: 'selectAll' };
147
+ if (e.key === 'Escape' && !mod && !e.shiftKey)
148
+ return hasSelection ? { kind: 'clear' } : null;
149
+ if (e.shiftKey && ARROW_KEYS.includes(e.key))
150
+ return { kind: 'extend', key: e.key, additive: mod };
151
+ return null;
152
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * createClickSelection: a reactive multi-selection for grids and lists that are
3
+ * used with the mouse (Shift-click ranges, Ctrl/⌘-click toggles) and the
4
+ * keyboard (Shift+arrows, Ctrl/⌘ A, Esc). The rules live in `clickSelection.ts`
5
+ * (pure, unit-tested); this wraps them in a `SvelteSet` plus `$state` ends so a
6
+ * component re-renders when the selection changes.
7
+ *
8
+ * Usage:
9
+ *
10
+ * const sel = createClickSelection({ ids: () => items.map((i) => i.id) });
11
+ *
12
+ * {#each items as item (item.id)}
13
+ * <button class:selected={sel.has(item.id)} onclick={(e) => sel.click(item.id, e)}>…</button>
14
+ * {/each}
15
+ *
16
+ * <svelte:window onkeydown={(e) => sel.handleKeydown(e, { next: (from, key) => neighbour(from, key) })} />
17
+ *
18
+ * <BulkActionBar selection={sel.ordered} actions={…} onClear={() => sel.clear()} />
19
+ *
20
+ * `ids()` is read on every call, in display order, so ranges always follow
21
+ * what is on screen; ids that left it are never reported (`ordered`,
22
+ * `picked`, `count`) and are dropped from the set on the next change.
23
+ *
24
+ * With listNav: listNav is the keyboard-only list motion (j/k, vim counts) and
25
+ * has its own opt-in selection (x, V, Shift+J/K). Give a surface ONE selection
26
+ * owner. A pointer-first grid uses clickSelection; a keyboard-first list uses
27
+ * listNav's. To have both, run listNav with `selectable: false` for focus
28
+ * motion and let clickSelection own the set: call `sel.click(id, e)` from the
29
+ * click handler and `sel.extendTo(id)` from your own Shift+J/K.
30
+ */
31
+ import { SvelteSet } from 'svelte/reactivity';
32
+ import { type ArrowKey, type SelectionKeyEvent, type SelectionModifiers } from './clickSelection';
33
+ export interface ClickSelectionOptions<Id = string> {
34
+ /** Every selectable id, in the order shown. Read lazily on each call. */
35
+ ids: () => readonly Id[];
36
+ /** Called after every change, with the selection in display order. */
37
+ onChange?: (ordered: Id[]) => void;
38
+ }
39
+ export interface ClickSelectionKeyOptions<Id = string> {
40
+ /**
41
+ * Where an arrow lands from `from` (null: the selection has no moving end
42
+ * yet). Return null to do nothing (an edge). Only the caller knows the
43
+ * layout (a grid's row above, a list's next item), so it decides.
44
+ */
45
+ next?: (from: Id | null, key: ArrowKey) => Id | null;
46
+ }
47
+ export interface ClickSelection<Id = string> {
48
+ /** The raw set (may briefly hold an id that just left `ids`; prefer `ordered`). */
49
+ readonly selected: SvelteSet<Id>;
50
+ /** The fixed end of a range: the last plain or Ctrl/⌘ click. */
51
+ readonly anchor: Id | null;
52
+ /** The moving end: the last id clicked or extended to. */
53
+ readonly head: Id | null;
54
+ /** Selected and still present, in display order. */
55
+ readonly ordered: Id[];
56
+ /** Selected and still present, in the order they were picked. */
57
+ readonly picked: Id[];
58
+ /** How many are selected and present. */
59
+ readonly count: number;
60
+ has(id: Id): boolean;
61
+ /** Apply a click with its modifiers (MouseEvent works as is). */
62
+ click(id: Id, mods?: SelectionModifiers): void;
63
+ /** Select only this one (a plain click or a plain arrow move). */
64
+ only(id: Id): void;
65
+ /** Toggle one (Ctrl/⌘ click, or an "x" key). */
66
+ toggle(id: Id): void;
67
+ /** Range from the anchor to `id`; `additive` keeps the rest. */
68
+ extendTo(id: Id, additive?: boolean): void;
69
+ selectAll(): void;
70
+ clear(): void;
71
+ /** Drop ids no longer in `ids()`. Every other method does this first. */
72
+ prune(): void;
73
+ /**
74
+ * Ctrl/⌘ A, Esc (while something is selected) and Shift+arrows (with
75
+ * `next`). Returns true and prevents the default when it handled the key.
76
+ */
77
+ handleKeydown(e: KeyboardEvent | SelectionKeyEvent, opts?: ClickSelectionKeyOptions<Id>): boolean;
78
+ }
79
+ export declare function createClickSelection<Id = string>(options: ClickSelectionOptions<Id>): ClickSelection<Id>;
@@ -0,0 +1,134 @@
1
+ /* createClickSelection.svelte.js generated by Svelte v5.53.11 */
2
+ import * as $ from 'svelte/internal/client';
3
+ import { SvelteSet } from 'svelte/reactivity';
4
+
5
+ import {
6
+ applyClick,
7
+ clearSelection,
8
+ extendTo,
9
+ inOrder,
10
+ inPickOrder,
11
+ prune,
12
+ selectAll,
13
+ selectionKey,
14
+ selectOnly,
15
+ toggleOne
16
+ } from './clickSelection';
17
+
18
+ export function createClickSelection(options) {
19
+ const selected = new SvelteSet();
20
+ let anchor = $.state(null);
21
+ let head = $.state(null);
22
+
23
+ const state = {
24
+ selected,
25
+ get anchor() {
26
+ return $.get(anchor);
27
+ },
28
+
29
+ set anchor(v) {
30
+ $.set(anchor, v, true);
31
+ },
32
+
33
+ get head() {
34
+ return $.get(head);
35
+ },
36
+
37
+ set head(v) {
38
+ $.set(head, v, true);
39
+ }
40
+ };
41
+
42
+ const ids = () => options.ids();
43
+ const changed = () => options.onChange?.(inOrder(selected, ids()));
44
+
45
+ return {
46
+ selected,
47
+ get anchor() {
48
+ return $.get(anchor);
49
+ },
50
+
51
+ get head() {
52
+ return $.get(head);
53
+ },
54
+
55
+ get ordered() {
56
+ return inOrder(selected, ids());
57
+ },
58
+
59
+ get picked() {
60
+ return inPickOrder(selected, ids());
61
+ },
62
+
63
+ get count() {
64
+ return inOrder(selected, ids()).length;
65
+ },
66
+ has: (id) => selected.has(id) && ids().includes(id),
67
+ click(id, mods = {}) {
68
+ applyClick(state, ids(), id, mods);
69
+ changed();
70
+ },
71
+
72
+ only(id) {
73
+ prune(state, ids());
74
+ selectOnly(state, id);
75
+ changed();
76
+ },
77
+
78
+ toggle(id) {
79
+ prune(state, ids());
80
+ toggleOne(state, id);
81
+ changed();
82
+ },
83
+
84
+ extendTo(id, additive = false) {
85
+ const all = ids();
86
+
87
+ prune(state, all);
88
+ extendTo(state, all, id, additive);
89
+ changed();
90
+ },
91
+
92
+ selectAll() {
93
+ selectAll(state, ids());
94
+ changed();
95
+ },
96
+
97
+ clear() {
98
+ clearSelection(state);
99
+ changed();
100
+ },
101
+
102
+ prune() {
103
+ if (prune(state, ids())) changed();
104
+ },
105
+
106
+ handleKeydown(e, opts = {}) {
107
+ const all = ids();
108
+ const action = selectionKey(e, inOrder(selected, all).length > 0);
109
+
110
+ if (!action) return false;
111
+
112
+ if (action.kind === 'extend') {
113
+ if (!opts.next) return false;
114
+
115
+ prune(state, all);
116
+
117
+ const to = opts.next($.get(head) ?? $.get(anchor), action.key);
118
+
119
+ if (to === null || to === undefined) {
120
+ e.preventDefault?.();
121
+
122
+ return true;
123
+ }
124
+
125
+ extendTo(state, all, to, action.additive);
126
+ } else if (action.kind === 'selectAll') selectAll(state, all); else clearSelection(state);
127
+
128
+ e.preventDefault?.();
129
+ changed();
130
+
131
+ return true;
132
+ }
133
+ };
134
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joewinke/jatui",
3
- "version": "0.38.6",
3
+ "version": "0.39.0",
4
4
  "private": false,
5
5
  "description": "Shared Svelte 5 component library for JAT projects",
6
6
  "type": "module",
@@ -84,7 +84,8 @@
84
84
  "dist",
85
85
  "CLAUDE.md",
86
86
  "README.md",
87
- "LICENSE"
87
+ "LICENSE",
88
+ "THIRD_PARTY_NOTICES.md"
88
89
  ],
89
90
  "scripts": {
90
91
  "dev": "npm run package && vite dev --port 5180",