@joewinke/jatui 0.38.5 → 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 (67) hide show
  1. package/CLAUDE.md +32 -1
  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/VideoPlayer.svelte +269 -3
  14. package/dist/components/agent/AgentLog.svelte +217 -0
  15. package/dist/components/agent/AgentLog.svelte.d.ts +72 -0
  16. package/dist/components/agent/AgentLogRow.svelte +281 -0
  17. package/dist/components/agent/AgentLogRow.svelte.d.ts +21 -0
  18. package/dist/components/agent/AgentTaskList.svelte +607 -0
  19. package/dist/components/agent/AgentTaskList.svelte.d.ts +40 -0
  20. package/dist/components/agent/AgentThinking.svelte +280 -0
  21. package/dist/components/agent/AgentThinking.svelte.d.ts +22 -0
  22. package/dist/components/agent/ComposerGlow.svelte +265 -0
  23. package/dist/components/agent/ComposerGlow.svelte.d.ts +18 -0
  24. package/dist/components/agent/ContextMeter.svelte +277 -0
  25. package/dist/components/agent/ContextMeter.svelte.d.ts +21 -0
  26. package/dist/components/agent/Questionnaire.svelte +767 -0
  27. package/dist/components/agent/Questionnaire.svelte.d.ts +29 -0
  28. package/dist/components/agent/ShimmerText.svelte +100 -0
  29. package/dist/components/agent/ShimmerText.svelte.d.ts +19 -0
  30. package/dist/components/agent/StreamedText.svelte +135 -0
  31. package/dist/components/agent/StreamedText.svelte.d.ts +13 -0
  32. package/dist/components/agent/agentLog.d.ts +22 -0
  33. package/dist/components/agent/agentLog.js +26 -0
  34. package/dist/components/agent/agentTaskList.d.ts +90 -0
  35. package/dist/components/agent/agentTaskList.js +93 -0
  36. package/dist/components/agent/agentThinking.d.ts +46 -0
  37. package/dist/components/agent/agentThinking.js +78 -0
  38. package/dist/components/agent/contextMeter.d.ts +97 -0
  39. package/dist/components/agent/contextMeter.js +156 -0
  40. package/dist/components/agent/questionnaire.d.ts +104 -0
  41. package/dist/components/agent/questionnaire.js +225 -0
  42. package/dist/components/agent/revealCore.d.ts +74 -0
  43. package/dist/components/agent/revealCore.js +160 -0
  44. package/dist/components/agent/revealTicker.d.ts +34 -0
  45. package/dist/components/agent/revealTicker.js +73 -0
  46. package/dist/components/agent/streamedText.d.ts +28 -0
  47. package/dist/components/agent/streamedText.js +59 -0
  48. package/dist/components/messaging/MessageInput.svelte +34 -4
  49. package/dist/components/messaging/MessageInput.svelte.d.ts +7 -0
  50. package/dist/components/messaging/MessageItem.svelte +2 -2
  51. package/dist/components/notificationCenter.d.ts +65 -0
  52. package/dist/components/notificationCenter.js +110 -0
  53. package/dist/components/progress/Steps.svelte +269 -5
  54. package/dist/components/progress/Steps.svelte.d.ts +16 -1
  55. package/dist/components/progress/stepsSummary.d.ts +14 -0
  56. package/dist/components/progress/stepsSummary.js +32 -0
  57. package/dist/index.d.ts +34 -0
  58. package/dist/index.js +29 -0
  59. package/dist/selection/clickSelection.d.ts +89 -0
  60. package/dist/selection/clickSelection.js +152 -0
  61. package/dist/selection/createClickSelection.d.ts +79 -0
  62. package/dist/selection/createClickSelection.js +134 -0
  63. package/dist/video/keys.d.ts +5 -5
  64. package/dist/video/keys.js +9 -5
  65. package/dist/video/transcriptSearch.d.ts +80 -0
  66. package/dist/video/transcriptSearch.js +153 -0
  67. package/package.json +3 -2
@@ -1,4 +1,24 @@
1
+ <!--
2
+ Steps — a numbered step track with an animated connector fill.
3
+
4
+ Opt-in extras (jatui-lltq9; none of them change the default output):
5
+ collapsible a summary header button ("3 steps left") that folds the
6
+ track away; the summary stays live while folded, and the
7
+ folded header also shows the active step's label + ring.
8
+ activeProgress 0–1 → a mini ProgressRing on the active step's node.
9
+ orientation 'vertical' stacks the steps (labels + descriptions beside
10
+ the nodes) — the shape for agent-progress / todo cards.
11
+ onFinished fires once, `completionDelay` ms after `current` passes the
12
+ last step (re-arms if `current` drops back), so a host can
13
+ hand the surface back to the agent's answer.
14
+ Drive `current` from real events; there is no time-simulated stepping.
15
+ -->
1
16
  <script lang="ts">
17
+ import { untrack, type Snippet } from 'svelte';
18
+ import ProgressRing from './ProgressRing.svelte';
19
+ import { motionSlide } from '../../motion/transitions';
20
+ import { clampStepProgress, isStepsFinished, stepsSummary } from './stepsSummary';
21
+
2
22
  interface Step {
3
23
  label?: string;
4
24
  description?: string;
@@ -10,6 +30,20 @@
10
30
  color?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info';
11
31
  size?: 'sm' | 'md' | 'lg';
12
32
  class?: string;
33
+ /** Render a summary header button that folds the steps away. */
34
+ collapsible?: boolean;
35
+ /** Folded state (bindable). Only meaningful with `collapsible`. */
36
+ collapsed?: boolean;
37
+ /** Header copy. Default: "N steps left" / "All steps done". */
38
+ summary?: string | Snippet;
39
+ /** Layout. Default 'horizontal'. */
40
+ orientation?: 'horizontal' | 'vertical';
41
+ /** 0–1 progress of the active step → a mini ring on its node. */
42
+ activeProgress?: number;
43
+ /** Hold (ms) after the last step completes before `onFinished`. Default 0. */
44
+ completionDelay?: number;
45
+ /** Fired once after `current` passes the last step (+ `completionDelay`). */
46
+ onFinished?: () => void;
13
47
  }
14
48
 
15
49
  let {
@@ -17,7 +51,14 @@
17
51
  current = 1,
18
52
  color = 'primary',
19
53
  size = 'md',
20
- class: className = ''
54
+ class: className = '',
55
+ collapsible = false,
56
+ collapsed = $bindable(false),
57
+ summary,
58
+ orientation = 'horizontal',
59
+ activeProgress,
60
+ completionDelay = 0,
61
+ onFinished
21
62
  }: Props = $props();
22
63
 
23
64
  const normalized = $derived(
@@ -53,17 +94,45 @@
53
94
  const nodePx = $derived(nodeSize[size]);
54
95
  const fontSize: Record<NonNullable<Props['size']>, string> = { sm: '0.6875rem', md: '0.8125rem', lg: '1rem' };
55
96
  const labelSize = $derived(fontSize[size]);
97
+
98
+ // ── Opt-in extras ────────────────────────────────────────────────────
99
+ const uid = $props.id();
100
+ const bodyId = `steps-body-${uid}`;
101
+ const vertical = $derived(orientation === 'vertical');
102
+ const finished = $derived(isStepsFinished(count, current));
103
+ const ringValue = $derived(
104
+ activeProgress == null ? null : Math.round(clampStepProgress(activeProgress) * 100)
105
+ );
106
+ const summaryText = $derived(typeof summary === 'string' ? summary : stepsSummary(count, current));
107
+ const activeLabel = $derived(finished ? undefined : normalized[current - 1]?.label);
108
+
109
+ // onFinished: once per "run" — re-arms when current drops back to a step.
110
+ let finishedFired = false;
111
+ $effect(() => {
112
+ if (!finished) {
113
+ finishedFired = false;
114
+ return;
115
+ }
116
+ if (finishedFired) return;
117
+ const delay = Math.max(0, completionDelay);
118
+ const timer = setTimeout(() => {
119
+ finishedFired = true;
120
+ untrack(() => onFinished)?.();
121
+ }, delay);
122
+ return () => clearTimeout(timer);
123
+ });
56
124
  </script>
57
125
 
126
+ {#snippet track()}
58
127
  <div
59
- class="steps-wrap {className}"
128
+ class="steps-wrap {collapsible ? '' : className}{vertical ? ' steps-wrap--vertical' : ''}"
60
129
  role="list"
61
130
  aria-label="Progress steps"
62
131
  style="--fill:{fillColor};--fg:{fgColor};--node:{nodePx}px"
63
132
  >
64
133
  <!-- Connector track -->
65
134
  <div class="steps-track" aria-hidden="true">
66
- <div class="steps-track-fill" style="transform:scaleX({trackFill})"></div>
135
+ <div class="steps-track-fill" style="transform:{vertical ? 'scaleY' : 'scaleX'}({trackFill})"></div>
67
136
  </div>
68
137
 
69
138
  <!-- Step nodes -->
@@ -78,7 +147,7 @@
78
147
  role="listitem"
79
148
  aria-current={isActive ? 'step' : undefined}
80
149
  >
81
- <div class="step-node" style="font-size:{labelSize}">
150
+ <div class="step-node" class:step-node--ring={isActive && ringValue != null} style="font-size:{labelSize}">
82
151
  {#if isComplete}
83
152
  <!-- Check mark drawn in on complete -->
84
153
  <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="step-check" aria-hidden="true">
@@ -86,14 +155,71 @@
86
155
  </svg>
87
156
  {:else}
88
157
  <span>{stepNum}</span>
158
+ {/if}{#if isActive && ringValue != null}
159
+ <span class="step-ring">
160
+ <ProgressRing
161
+ value={ringValue}
162
+ size={nodePx}
163
+ strokeWidth={size === 'sm' ? 2 : 3}
164
+ {color}
165
+ showValue={false}
166
+ label="{step.label ?? `Step ${stepNum}`} progress"
167
+ />
168
+ </span>
89
169
  {/if}
90
170
  </div>
91
- {#if step.label}
171
+ {#if vertical}
172
+ {#if step.label || step.description}
173
+ <span class="step-text">
174
+ {#if step.label}<span class="step-label" style="font-size:{labelSize}">{step.label}</span>{/if}
175
+ {#if step.description}<span class="step-desc">{step.description}</span>{/if}
176
+ </span>
177
+ {/if}
178
+ {:else if step.label}
92
179
  <span class="step-label" style="font-size:{labelSize}">{step.label}</span>
93
180
  {/if}
94
181
  </div>
95
182
  {/each}
96
183
  </div>
184
+ {/snippet}
185
+
186
+ {#if collapsible}
187
+ <div class="steps-fold {className}" style="--fill:{fillColor}">
188
+ <button
189
+ type="button"
190
+ class="steps-fold-header"
191
+ aria-expanded={!collapsed}
192
+ aria-controls={bodyId}
193
+ onclick={() => (collapsed = !collapsed)}
194
+ >
195
+ <svg class="steps-fold-chevron" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
196
+ <polyline points="6,4 10,8 6,12" />
197
+ </svg>
198
+ <span class="steps-fold-summary">
199
+ {#if typeof summary === 'function'}{@render summary()}{:else}{summaryText}{/if}
200
+ </span>
201
+ {#if collapsed && activeLabel}
202
+ <span class="steps-fold-current">{activeLabel}</span>
203
+ {/if}
204
+ {#if collapsed && ringValue != null && !finished}
205
+ <span class="steps-fold-ring" aria-hidden="true">
206
+ <ProgressRing value={ringValue} size={16} strokeWidth={2} {color} showValue={false} />
207
+ </span>
208
+ {/if}
209
+ </button>
210
+ <!-- Live summary for assistive tech — the header text itself is not a live region. -->
211
+ <span class="sr-only" aria-live="polite">{summaryText}</span>
212
+ <div id={bodyId} class="steps-fold-body">
213
+ {#if !collapsed}
214
+ <div class="steps-fold-inner" transition:motionSlide>
215
+ {@render track()}
216
+ </div>
217
+ {/if}
218
+ </div>
219
+ </div>
220
+ {:else}
221
+ {@render track()}
222
+ {/if}
97
223
 
98
224
  <style>
99
225
  .steps-wrap {
@@ -136,6 +262,7 @@
136
262
  }
137
263
 
138
264
  .step-node {
265
+ position: relative;
139
266
  width: var(--node);
140
267
  height: var(--node);
141
268
  border-radius: 9999px;
@@ -160,6 +287,18 @@
160
287
  transform: scale(1.18);
161
288
  }
162
289
 
290
+ /* Active node with a progress ring: the ring IS the border. */
291
+ .step--active .step-node--ring {
292
+ border-color: transparent;
293
+ }
294
+
295
+ .step-ring {
296
+ position: absolute;
297
+ inset: -2px;
298
+ display: flex;
299
+ pointer-events: none;
300
+ }
301
+
163
302
  .step--complete .step-node {
164
303
  background: var(--fill);
165
304
  border-color: var(--fill);
@@ -184,6 +323,127 @@
184
323
  color: var(--color-base-content);
185
324
  }
186
325
 
326
+ /* ── Vertical orientation ─────────────────────────────────────────── */
327
+ .steps-wrap--vertical {
328
+ flex-direction: column;
329
+ align-items: stretch;
330
+ justify-content: flex-start;
331
+ gap: 0.875rem;
332
+ padding-top: 0;
333
+ }
334
+
335
+ .steps-wrap--vertical .steps-track {
336
+ top: calc(var(--node) / 2);
337
+ bottom: calc(var(--node) / 2);
338
+ left: calc(var(--node) / 2);
339
+ right: auto;
340
+ width: 3px;
341
+ height: auto;
342
+ transform: translateX(-50%);
343
+ }
344
+
345
+ .steps-wrap--vertical .steps-track-fill {
346
+ width: 100%;
347
+ transform-origin: top;
348
+ }
349
+
350
+ .steps-wrap--vertical .step {
351
+ flex-direction: row;
352
+ align-items: flex-start;
353
+ gap: 0.75rem;
354
+ }
355
+
356
+ .steps-wrap--vertical .step-node {
357
+ flex-shrink: 0;
358
+ }
359
+
360
+ .step-text {
361
+ display: flex;
362
+ flex-direction: column;
363
+ gap: 0.125rem;
364
+ min-width: 0;
365
+ min-height: var(--node);
366
+ justify-content: center;
367
+ }
368
+
369
+ .steps-wrap--vertical .step-label {
370
+ text-align: left;
371
+ max-width: none;
372
+ }
373
+
374
+ .step-desc {
375
+ font-size: 0.75rem;
376
+ line-height: 1.3;
377
+ color: color-mix(in oklch, var(--color-base-content) 55%, transparent);
378
+ }
379
+
380
+ /* ── Collapsible header ───────────────────────────────────────────── */
381
+ .steps-fold {
382
+ width: 100%;
383
+ }
384
+
385
+ .steps-fold-header {
386
+ display: flex;
387
+ align-items: center;
388
+ gap: 0.5rem;
389
+ width: 100%;
390
+ min-height: 2.25rem;
391
+ padding: 0.375rem 0.5rem;
392
+ border-radius: var(--jatui-radius-field, var(--radius-field, 0.25rem));
393
+ font-size: 0.875rem;
394
+ font-weight: 600;
395
+ text-align: left;
396
+ color: var(--color-base-content);
397
+ background: transparent;
398
+ cursor: pointer;
399
+ transition: background var(--motion-fast, 150ms) var(--motion-glide);
400
+ }
401
+
402
+ .steps-fold-header:hover {
403
+ background: color-mix(in oklch, var(--color-base-content) 6%, transparent);
404
+ }
405
+
406
+ .steps-fold-header:focus-visible {
407
+ outline: 2px solid var(--fill);
408
+ outline-offset: 2px;
409
+ }
410
+
411
+ .steps-fold-chevron {
412
+ width: 1rem;
413
+ height: 1rem;
414
+ flex-shrink: 0;
415
+ color: color-mix(in oklch, var(--color-base-content) 55%, transparent);
416
+ transform: rotate(90deg);
417
+ transition: transform var(--motion-fast, 150ms) var(--motion-glide);
418
+ }
419
+
420
+ .steps-fold-header[aria-expanded='false'] .steps-fold-chevron {
421
+ transform: rotate(0deg);
422
+ }
423
+
424
+ .steps-fold-summary {
425
+ font-variant-numeric: tabular-nums;
426
+ }
427
+
428
+ .steps-fold-current {
429
+ min-width: 0;
430
+ overflow: hidden;
431
+ text-overflow: ellipsis;
432
+ white-space: nowrap;
433
+ font-weight: 400;
434
+ color: color-mix(in oklch, var(--color-base-content) 60%, transparent);
435
+ }
436
+
437
+ .steps-fold-ring {
438
+ display: inline-flex;
439
+ margin-left: auto;
440
+ flex-shrink: 0;
441
+ }
442
+
443
+ .steps-fold-inner {
444
+ padding: 0.5rem 0.25rem 0.25rem;
445
+ }
446
+
187
447
  @media (prefers-reduced-motion: reduce) {
188
448
  .steps-track-fill {
189
449
  transition: none;
@@ -191,5 +451,9 @@
191
451
  .step-node {
192
452
  transition: none;
193
453
  }
454
+ .steps-fold-chevron,
455
+ .steps-fold-header {
456
+ transition: none;
457
+ }
194
458
  }
195
459
  </style>
@@ -1,3 +1,4 @@
1
+ import { type Snippet } from 'svelte';
1
2
  interface Step {
2
3
  label?: string;
3
4
  description?: string;
@@ -8,7 +9,21 @@ interface Props {
8
9
  color?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info';
9
10
  size?: 'sm' | 'md' | 'lg';
10
11
  class?: string;
12
+ /** Render a summary header button that folds the steps away. */
13
+ collapsible?: boolean;
14
+ /** Folded state (bindable). Only meaningful with `collapsible`. */
15
+ collapsed?: boolean;
16
+ /** Header copy. Default: "N steps left" / "All steps done". */
17
+ summary?: string | Snippet;
18
+ /** Layout. Default 'horizontal'. */
19
+ orientation?: 'horizontal' | 'vertical';
20
+ /** 0–1 progress of the active step → a mini ring on its node. */
21
+ activeProgress?: number;
22
+ /** Hold (ms) after the last step completes before `onFinished`. Default 0. */
23
+ completionDelay?: number;
24
+ /** Fired once after `current` passes the last step (+ `completionDelay`). */
25
+ onFinished?: () => void;
11
26
  }
12
- declare const Steps: import("svelte").Component<Props, {}, "">;
27
+ declare const Steps: import("svelte").Component<Props, {}, "collapsed">;
13
28
  type Steps = ReturnType<typeof Steps>;
14
29
  export default Steps;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Pure helpers behind Steps' collapsible summary header (jatui-lltq9).
3
+ *
4
+ * `current` is Steps' 1-based active step: steps before it are complete, the
5
+ * step at it is in progress, and `current > count` means every step is done.
6
+ */
7
+ /** Steps still to finish, counting the active one. Never negative. */
8
+ export declare function stepsRemaining(count: number, current: number): number;
9
+ /** True once `current` has moved past the last step. */
10
+ export declare function isStepsFinished(count: number, current: number): boolean;
11
+ /** Default header copy: "3 steps left", "1 step left", "All steps done". */
12
+ export declare function stepsSummary(count: number, current: number): string;
13
+ /** Clamp an active-step progress fraction to 0–1 (non-finite → 0). */
14
+ export declare function clampStepProgress(value: number): number;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Pure helpers behind Steps' collapsible summary header (jatui-lltq9).
3
+ *
4
+ * `current` is Steps' 1-based active step: steps before it are complete, the
5
+ * step at it is in progress, and `current > count` means every step is done.
6
+ */
7
+ /** Steps still to finish, counting the active one. Never negative. */
8
+ export function stepsRemaining(count, current) {
9
+ if (!Number.isFinite(count) || count <= 0)
10
+ return 0;
11
+ const done = Math.max(0, Math.min(count, Math.floor(current) - 1));
12
+ return count - done;
13
+ }
14
+ /** True once `current` has moved past the last step. */
15
+ export function isStepsFinished(count, current) {
16
+ return count > 0 && current > count;
17
+ }
18
+ /** Default header copy: "3 steps left", "1 step left", "All steps done". */
19
+ export function stepsSummary(count, current) {
20
+ if (!Number.isFinite(count) || count <= 0)
21
+ return 'No steps';
22
+ const left = stepsRemaining(count, current);
23
+ if (left === 0)
24
+ return 'All steps done';
25
+ return `${left} ${left === 1 ? 'step' : 'steps'} left`;
26
+ }
27
+ /** Clamp an active-step progress fraction to 0–1 (non-finite → 0). */
28
+ export function clampStepProgress(value) {
29
+ if (!Number.isFinite(value))
30
+ return 0;
31
+ return value < 0 ? 0 : value > 1 ? 1 : value;
32
+ }
package/dist/index.d.ts CHANGED
@@ -57,6 +57,10 @@ export { default as InlineEdit } from './components/InlineEdit.svelte';
57
57
  export { default as FloatingActionBar } from './components/FloatingActionBar.svelte';
58
58
  export { default as BulkActionBar } from './components/BulkActionBar.svelte';
59
59
  export type { BulkAction, BulkActionGroup } from './components/BulkActionBar.svelte';
60
+ export { createClickSelection } from './selection/createClickSelection';
61
+ export type { ClickSelection, ClickSelectionOptions, ClickSelectionKeyOptions } from './selection/createClickSelection';
62
+ export { applyClick as applySelectionClick, extendTo as extendSelectionTo, rangeBetween as selectionRange, selectionKey, isAdditive as isAdditiveClick } from './selection/clickSelection';
63
+ export type { SelectionModifiers, SelectionState, SelectionKeyEvent, SelectionKeyAction, ArrowKey as SelectionArrowKey } from './selection/clickSelection';
60
64
  export { default as HunkDiffView } from './components/HunkDiffView.svelte';
61
65
  export { default as Tooltip } from './components/Tooltip.svelte';
62
66
  export { default as PresenceStack } from './components/PresenceStack.svelte';
@@ -205,6 +209,8 @@ export type { AttentionEffect, AttentionOptions } from './actions/attention';
205
209
  export { reveal, REVEAL_HIDDEN_CLASS, REVEAL_BASE_CLASS, REVEAL_OFF_SELECTOR, REVEAL_MAX_DELAY_SECONDS } from './actions/reveal';
206
210
  export type { RevealOptions, RevealVariant } from './actions/reveal';
207
211
  export { default as ThumbnailGrid } from './components/ThumbnailGrid.svelte';
212
+ export { default as MediaExplorer } from "./components/MediaExplorer.svelte";
213
+ export type { ExplorerSource } from "./components/MediaExplorer.svelte";
208
214
  export type { ThumbnailItem } from './components/ThumbnailGrid.svelte';
209
215
  export { floating, makeVirtualAnchor } from './actions/floating';
210
216
  export type { FloatingOptions, Placement } from './actions/floating';
@@ -304,3 +310,31 @@ export { mergeReviewCounts, summarizeReview, reviewSentence, buildReviewFilters,
304
310
  export type { ReviewTone, ReviewVerdictDef, ReviewCounts, ReviewRound, ReviewFilterChip, ReviewSummary, BuildFiltersInput } from './components/review/reviewSummary';
305
311
  export { MEDIA_ZOOM_KEYS, mediaZoomHint } from './components/review/mediaZoom';
306
312
  export type { MediaZoomState, MediaZoomView, MediaZoomFooterContext, MediaZoomAction, MediaZoomKeyDef, MediaZoomKeyContext } from './components/review/mediaZoom';
313
+ export { default as ShimmerText } from './components/agent/ShimmerText.svelte';
314
+ export { default as AgentThinking } from './components/agent/AgentThinking.svelte';
315
+ export { formatThinkingTime } from './components/agent/agentThinking';
316
+ export type { AgentThinkingVariant, AgentThinkingTone } from './components/agent/agentThinking';
317
+ export { default as AgentLog } from './components/agent/AgentLog.svelte';
318
+ export { default as AgentLogRow } from './components/agent/AgentLogRow.svelte';
319
+ export { createRevealTicker } from './components/agent/revealTicker';
320
+ export type { RevealTickerOptions, RevealTicker } from './components/agent/revealTicker';
321
+ export { RevealCore, revealDelay, DEFAULT_STEP_INTERVAL as REVEAL_STEP_INTERVAL, DEFAULT_START_DELAY as REVEAL_START_DELAY } from './components/agent/revealCore';
322
+ export type { RevealCoreOptions, RevealClock, RevealCoreHooks } from './components/agent/revealCore';
323
+ export { BRANCH_Y as AGENT_LOG_BRANCH_Y } from './components/agent/agentLog';
324
+ export { default as AgentTaskList } from './components/agent/AgentTaskList.svelte';
325
+ export { countUnits as countAgentTaskUnits, layoutTaskReveal, displayStatus as agentTaskDisplayStatus, isListComplete as isAgentTaskListComplete, foldedByPolicy as agentTaskFoldedByPolicy, sourceStack as agentSourceStack, sourceDomain as agentSourceDomain, sourceLabel as agentSourceLabel } from './components/agent/agentTaskList';
326
+ export type { AgentTask, AgentTaskStep, AgentTaskChip, AgentTaskSource, AgentTaskStatus, CollapsePolicy as AgentTaskCollapsePolicy, TaskReveal } from './components/agent/agentTaskList';
327
+ export { default as Questionnaire } from './components/agent/Questionnaire.svelte';
328
+ export { emptyAnswers as emptyQuestionnaireAnswers, normalizeAnswers as normalizeQuestionnaireAnswers, finalizeAnswers as finalizeQuestionnaireAnswers, isComplete as isQuestionnaireComplete, isAnswered as isQuestionAnswered, digitToRow as questionnaireDigitToRow } from './components/agent/questionnaire';
329
+ export type { QuestionnaireQuestion, QuestionnaireOption, QuestionnaireAnswer, QuestionnaireAnswers } from './components/agent/questionnaire';
330
+ export { default as ContextMeter } from './components/agent/ContextMeter.svelte';
331
+ export { computeContextMeter, buildBreakdown as buildContextBreakdown, formatCompact as formatCompactTokens, formatPercent as formatContextPercent, segmentColor as contextSegmentColor, meterValueText as contextMeterValueText } from './components/agent/contextMeter';
332
+ export type { ContextSegment, ContextGroup, ContextTone, ContextMeterModel, MeterSegment as ContextMeterSegment, BreakdownRow as ContextBreakdownRow } from './components/agent/contextMeter';
333
+ export { default as ComposerGlow } from './components/agent/ComposerGlow.svelte';
334
+ export { default as StreamedText } from './components/agent/StreamedText.svelte';
335
+ export { splitStreamedText } from './components/agent/streamedText';
336
+ export type { StreamedBlock, StreamedTextSplit } from './components/agent/streamedText';
337
+ export { stepsSummary, stepsRemaining, isStepsFinished, clampStepProgress } from './components/progress/stepsSummary';
338
+ export { default as NotificationCenter } from './components/NotificationCenter.svelte';
339
+ export { DEFAULT_NOTIFICATION_TABS, DATE_GROUP_LABELS as NOTIFICATION_DATE_GROUP_LABELS, dateGroupKey as notificationDateGroupKey, groupNotificationsByDate, toTimestampMs as notificationTimestampMs, isNotificationUnread, unreadIds as unreadNotificationIds, filterByTab as filterNotificationsByTab, tabCounts as notificationTabCounts, unreadSummary as notificationUnreadSummary } from './components/notificationCenter';
340
+ export type { NotificationItem, NotificationAction, NotificationTab, NotificationStatus, NotificationGroup, DateGroupKey as NotificationDateGroupKey } from './components/notificationCenter';
package/dist/index.js CHANGED
@@ -93,6 +93,12 @@ export { default as SortDropdown } from './components/SortDropdown.svelte';
93
93
  export { default as InlineEdit } from './components/InlineEdit.svelte';
94
94
  export { default as FloatingActionBar } from './components/FloatingActionBar.svelte';
95
95
  export { default as BulkActionBar } from './components/BulkActionBar.svelte';
96
+ // Click selection (qimg-x9ifp.1): the pointer-first multi-selection that feeds
97
+ // BulkActionBar — click / Ctrl-⌘ click / Shift click ranges, Shift+arrows,
98
+ // Ctrl/⌘ A, Esc. Pure rules in selection/clickSelection.ts (unit-tested), a
99
+ // reactive SvelteSet controller in createClickSelection.svelte.ts.
100
+ export { createClickSelection } from './selection/createClickSelection';
101
+ export { applyClick as applySelectionClick, extendTo as extendSelectionTo, rangeBetween as selectionRange, selectionKey, isAdditive as isAdditiveClick } from './selection/clickSelection';
96
102
  export { default as HunkDiffView } from './components/HunkDiffView.svelte';
97
103
  // Primitives — accessibility + form-editor scaffolding
98
104
  export { default as Tooltip } from './components/Tooltip.svelte';
@@ -248,6 +254,7 @@ export { reveal, REVEAL_HIDDEN_CLASS, REVEAL_BASE_CLASS, REVEAL_OFF_SELECTOR, RE
248
254
  // Thumbnail grid (jatui-m4uz3.3, chimaro port): generic {id,url,alt} strip
249
255
  // with overflow counter, remove/add affordances and a cell snippet override.
250
256
  export { default as ThumbnailGrid } from './components/ThumbnailGrid.svelte';
257
+ export { default as MediaExplorer } from "./components/MediaExplorer.svelte";
251
258
  export { floating, makeVirtualAnchor } from './actions/floating';
252
259
  export { glide } from './transitions/glide';
253
260
  // View Transitions kit
@@ -355,3 +362,25 @@ export { default as MediaZoomLightbox } from './components/review/MediaZoomLight
355
362
  export { reviewKeys, createReviewKeys, reviewKeyRows, resolveReviewKey, REVIEW_KEY_TABLE } from './actions/reviewKeys';
356
363
  export { mergeReviewCounts, summarizeReview, reviewSentence, buildReviewFilters, orderRounds, formatRoundDate } from './components/review/reviewSummary';
357
364
  export { MEDIA_ZOOM_KEYS, mediaZoomHint } from './components/review/mediaZoom';
365
+ // Agent surfaces (BoardUI wave 2 — jatui-lltq9). Free BoardUI items are MIT
366
+ // (THIRD_PARTY_NOTICES.md); Task List / Questionnaire / ContextMeter are clean-room.
367
+ export { default as ShimmerText } from './components/agent/ShimmerText.svelte';
368
+ export { default as AgentThinking } from './components/agent/AgentThinking.svelte';
369
+ export { formatThinkingTime } from './components/agent/agentThinking';
370
+ export { default as AgentLog } from './components/agent/AgentLog.svelte';
371
+ export { default as AgentLogRow } from './components/agent/AgentLogRow.svelte';
372
+ export { createRevealTicker } from './components/agent/revealTicker';
373
+ export { RevealCore, revealDelay, DEFAULT_STEP_INTERVAL as REVEAL_STEP_INTERVAL, DEFAULT_START_DELAY as REVEAL_START_DELAY } from './components/agent/revealCore';
374
+ export { BRANCH_Y as AGENT_LOG_BRANCH_Y } from './components/agent/agentLog';
375
+ export { default as AgentTaskList } from './components/agent/AgentTaskList.svelte';
376
+ export { countUnits as countAgentTaskUnits, layoutTaskReveal, displayStatus as agentTaskDisplayStatus, isListComplete as isAgentTaskListComplete, foldedByPolicy as agentTaskFoldedByPolicy, sourceStack as agentSourceStack, sourceDomain as agentSourceDomain, sourceLabel as agentSourceLabel } from './components/agent/agentTaskList';
377
+ export { default as Questionnaire } from './components/agent/Questionnaire.svelte';
378
+ export { emptyAnswers as emptyQuestionnaireAnswers, normalizeAnswers as normalizeQuestionnaireAnswers, finalizeAnswers as finalizeQuestionnaireAnswers, isComplete as isQuestionnaireComplete, isAnswered as isQuestionAnswered, digitToRow as questionnaireDigitToRow } from './components/agent/questionnaire';
379
+ export { default as ContextMeter } from './components/agent/ContextMeter.svelte';
380
+ export { computeContextMeter, buildBreakdown as buildContextBreakdown, formatCompact as formatCompactTokens, formatPercent as formatContextPercent, segmentColor as contextSegmentColor, meterValueText as contextMeterValueText } from './components/agent/contextMeter';
381
+ export { default as ComposerGlow } from './components/agent/ComposerGlow.svelte';
382
+ export { default as StreamedText } from './components/agent/StreamedText.svelte';
383
+ export { splitStreamedText } from './components/agent/streamedText';
384
+ export { stepsSummary, stepsRemaining, isStepsFinished, clampStepProgress } from './components/progress/stepsSummary';
385
+ export { default as NotificationCenter } from './components/NotificationCenter.svelte';
386
+ export { DEFAULT_NOTIFICATION_TABS, DATE_GROUP_LABELS as NOTIFICATION_DATE_GROUP_LABELS, dateGroupKey as notificationDateGroupKey, groupNotificationsByDate, toTimestampMs as notificationTimestampMs, isNotificationUnread, unreadIds as unreadNotificationIds, filterByTab as filterNotificationsByTab, tabCounts as notificationTabCounts, unreadSummary as notificationUnreadSummary } from './components/notificationCenter';
@@ -0,0 +1,89 @@
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
+ /** The modifier keys of a click (a MouseEvent or KeyboardEvent satisfies it). */
26
+ export interface SelectionModifiers {
27
+ shiftKey?: boolean;
28
+ ctrlKey?: boolean;
29
+ metaKey?: boolean;
30
+ }
31
+ /** What a selection is: the set, plus the fixed and the moving end of a range. */
32
+ export interface SelectionState<Id = string> {
33
+ selected: Set<Id>;
34
+ anchor: Id | null;
35
+ head: Id | null;
36
+ }
37
+ /** Ctrl on Linux/Windows, ⌘ on macOS: either counts as "toggle / add". */
38
+ export declare const isAdditive: (m: SelectionModifiers) => boolean;
39
+ /** The ids from `a` to `b` inclusive, in `ids` order (either direction). Empty when either is missing. */
40
+ export declare function rangeBetween<Id>(ids: readonly Id[], a: Id, b: Id): Id[];
41
+ /** Select only `id` and make it the anchor (a plain click, or a plain arrow move). */
42
+ export declare function selectOnly<Id>(s: SelectionState<Id>, id: Id): void;
43
+ /** Toggle `id` and make it the anchor (Ctrl/⌘ click). */
44
+ export declare function toggleOne<Id>(s: SelectionState<Id>, id: Id): void;
45
+ /**
46
+ * Select the range from the anchor to `id` (Shift click / Shift arrows).
47
+ * `additive` keeps what was selected and adds the range (Shift+Ctrl/⌘).
48
+ * With no usable anchor (none yet, or it vanished) it behaves as a plain
49
+ * click on `id` (or a toggle-on when additive).
50
+ */
51
+ export declare function extendTo<Id>(s: SelectionState<Id>, ids: readonly Id[], id: Id, additive?: boolean): void;
52
+ /** Apply one click on `id` with its modifiers. Ids not in `ids` are ignored. */
53
+ export declare function applyClick<Id>(s: SelectionState<Id>, ids: readonly Id[], id: Id, m?: SelectionModifiers): void;
54
+ /** Select every id (Ctrl/⌘ A). The anchor stays if it is still there, else the first id. */
55
+ export declare function selectAll<Id>(s: SelectionState<Id>, ids: readonly Id[]): void;
56
+ /** Clear the selection and the range ends (Esc). */
57
+ export declare function clearSelection<Id>(s: SelectionState<Id>): void;
58
+ /** Drop selected ids that are no longer in `ids` (and an anchor or head that vanished). True when anything changed. */
59
+ export declare function prune<Id>(s: SelectionState<Id>, ids: readonly Id[]): boolean;
60
+ /** The selected ids that are still present, in `ids` order (what a range or a list shows). */
61
+ export declare const inOrder: <Id>(selected: ReadonlySet<Id>, ids: readonly Id[]) => Id[];
62
+ /** The selected ids that are still present, in the order they were selected (Set insertion order). */
63
+ export declare function inPickOrder<Id>(selected: ReadonlySet<Id>, ids: readonly Id[]): Id[];
64
+ /** The keyboard part of a keydown (a KeyboardEvent satisfies it). */
65
+ export interface SelectionKeyEvent extends SelectionModifiers {
66
+ key: string;
67
+ altKey?: boolean;
68
+ target?: EventTarget | null;
69
+ defaultPrevented?: boolean;
70
+ }
71
+ export declare const ARROW_KEYS: readonly ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"];
72
+ export type ArrowKey = (typeof ARROW_KEYS)[number];
73
+ /** What a selection key does, decided without touching anything. */
74
+ export type SelectionKeyAction = {
75
+ kind: 'selectAll';
76
+ } | {
77
+ kind: 'clear';
78
+ } | {
79
+ kind: 'extend';
80
+ key: ArrowKey;
81
+ additive: boolean;
82
+ };
83
+ /**
84
+ * Which selection key this is, if any: Ctrl/⌘ A (select all), Esc (clear,
85
+ * only while something is selected, so Esc keeps its other meanings when
86
+ * nothing is), Shift+arrows (extend; with Ctrl/⌘ too, add the range).
87
+ * Never while typing in a field, never with Alt, never when already handled.
88
+ */
89
+ export declare function selectionKey(e: SelectionKeyEvent, hasSelection: boolean): SelectionKeyAction | null;