@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
@@ -0,0 +1,280 @@
1
+ <!--
2
+ AgentThinking — the "agent is working" status line that sits above a
3
+ composer or at the tail of a transcript: a small indicator, a shimmering
4
+ label and an elapsed timer.
5
+
6
+ Variants (indicator geometry adapted from BoardUI's agent-thinking —
7
+ MIT License — Copyright (c) 2026 Mertcan Dundar Esmergul (BoardUI)):
8
+ wave 3×3 dot grid, a diagonal wavefront
9
+ spin 3×3 dot grid, a bright head orbiting clockwise
10
+ stars staggered sparkles
11
+ infinity a comet sweeping a figure-eight
12
+
13
+ Differences from the original: the dot comet is pure CSS (no 80 ms
14
+ setInterval re-render), the timer is aria-hidden so screen readers hear the
15
+ label once instead of a re-announcement every 100 ms, tones are tokens,
16
+ and `startedAt` lets a re-mounted row (virtualised list) keep the real
17
+ elapsed time.
18
+
19
+ Motion: the indicator carries meaning (work is in progress), so it keeps
20
+ running on data-motion="calm"; the label shimmer is decorative and stops
21
+ there. Under prefers-reduced-motion everything rests on a static frame.
22
+ -->
23
+ <script lang="ts">
24
+ import ShimmerText from './ShimmerText.svelte';
25
+ import {
26
+ DOT_SEED,
27
+ DOT_PERIOD_MS,
28
+ TONE_COLOR,
29
+ VARIANT_TONE,
30
+ dotDelayMs,
31
+ formatThinkingTime,
32
+ type AgentThinkingTone,
33
+ type AgentThinkingVariant
34
+ } from './agentThinking';
35
+
36
+ interface Props {
37
+ variant?: AgentThinkingVariant;
38
+ /** Status label, e.g. "Thinking" or "Searching the docs". */
39
+ label?: string;
40
+ /** Indicator + label tone. Defaults per variant (`stars` is subtle). */
41
+ tone?: AgentThinkingTone;
42
+ /** Travelling highlight across the label. */
43
+ shimmer?: boolean;
44
+ /** Elapsed time after the label. */
45
+ showTimer?: boolean;
46
+ /**
47
+ * When the work started (epoch ms, Date.now() basis). Defaults to mount
48
+ * time. Pass it when the row can re-mount so the timer keeps counting.
49
+ */
50
+ startedAt?: number;
51
+ size?: 'sm' | 'md';
52
+ class?: string;
53
+ }
54
+
55
+ let {
56
+ variant = 'wave',
57
+ label = 'Thinking',
58
+ tone,
59
+ shimmer = true,
60
+ showTimer = true,
61
+ startedAt,
62
+ size = 'md',
63
+ class: className = ''
64
+ }: Props = $props();
65
+
66
+ const toneKey = $derived(tone ?? VARIANT_TONE[variant]);
67
+ const color = $derived(TONE_COLOR[toneKey]);
68
+
69
+ const mountedAt = Date.now();
70
+ let now = $state(Date.now());
71
+ const elapsed = $derived(now - (startedAt ?? mountedAt));
72
+
73
+ $effect(() => {
74
+ if (!showTimer) return;
75
+ now = Date.now();
76
+ const id = setInterval(() => (now = Date.now()), 100);
77
+ return () => clearInterval(id);
78
+ });
79
+
80
+ const STAR_PERIOD_MS = 1400;
81
+ const STARS = [
82
+ { x: 50, y: 46, scale: 1 },
83
+ { x: 18, y: 22, scale: 0.55 },
84
+ { x: 82, y: 26, scale: 0.45 },
85
+ { x: 78, y: 76, scale: 0.55 },
86
+ { x: 22, y: 78, scale: 0.4 }
87
+ ];
88
+ const STAR_PATH = 'M12 0C13 7 17 11 24 12C17 13 13 17 12 24C11 17 7 13 0 12C7 11 11 7 12 0Z';
89
+ const INFINITY_PATH = 'M28 14C33 5 47 5 47 14C47 23 33 23 28 14C23 5 9 5 9 14C9 23 23 23 28 14Z';
90
+ </script>
91
+
92
+ <div
93
+ class="agent-thinking agent-thinking--{size} {className}"
94
+ role="status"
95
+ style:color
96
+ style:--at-period="{DOT_PERIOD_MS}ms"
97
+ >
98
+ {#if variant === 'wave' || variant === 'spin'}
99
+ <span class="at-dots" aria-hidden="true">
100
+ {#each DOT_SEED as seed, i (i)}
101
+ <span
102
+ class="at-dot"
103
+ style:--at-seed={seed}
104
+ style:animation-delay="{dotDelayMs(variant, i)}ms"
105
+ ></span>
106
+ {/each}
107
+ </span>
108
+ {:else if variant === 'stars'}
109
+ <span class="at-stars" aria-hidden="true">
110
+ {#each STARS as star, i (i)}
111
+ <svg
112
+ viewBox="0 0 24 24"
113
+ class="at-star"
114
+ style:width="{star.scale}em"
115
+ style:height="{star.scale}em"
116
+ style:left="{star.x}%"
117
+ style:top="{star.y}%"
118
+ style:animation-duration="{STAR_PERIOD_MS}ms"
119
+ style:animation-delay="{Math.round((i * STAR_PERIOD_MS * 0.7) / STARS.length)}ms"
120
+ >
121
+ <path d={STAR_PATH} fill="currentColor" />
122
+ </svg>
123
+ {/each}
124
+ </span>
125
+ {:else}
126
+ <svg class="at-infinity" viewBox="0 0 56 28" aria-hidden="true">
127
+ <path d={INFINITY_PATH} fill="none" stroke="currentColor" stroke-width="2.75" opacity="0.15" />
128
+ <path
129
+ class="at-comet"
130
+ d={INFINITY_PATH}
131
+ pathLength="100"
132
+ fill="none"
133
+ stroke="currentColor"
134
+ stroke-width="2.75"
135
+ stroke-linecap="round"
136
+ stroke-dasharray="11 89"
137
+ />
138
+ </svg>
139
+ {/if}
140
+
141
+ <ShimmerText class="at-label" text={label} tone={toneKey} active={shimmer} />
142
+
143
+ {#if showTimer}
144
+ <span class="at-timer" aria-hidden="true">{formatThinkingTime(elapsed)}</span>
145
+ {/if}
146
+ </div>
147
+
148
+ <style>
149
+ .agent-thinking {
150
+ display: inline-flex;
151
+ align-items: center;
152
+ gap: 0.625rem;
153
+ min-width: 0;
154
+ font-size: 0.875rem;
155
+ line-height: 1.25rem;
156
+ }
157
+ .agent-thinking--sm {
158
+ gap: 0.5rem;
159
+ font-size: 0.75rem;
160
+ line-height: 1rem;
161
+ }
162
+
163
+ .agent-thinking :global(.at-label) {
164
+ font-weight: 500;
165
+ min-width: 0;
166
+ overflow: hidden;
167
+ text-overflow: ellipsis;
168
+ white-space: nowrap;
169
+ }
170
+
171
+ .at-timer {
172
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
173
+ font-size: 0.75rem;
174
+ font-variant-numeric: tabular-nums;
175
+ color: color-mix(in oklab, var(--color-base-content) 50%, transparent);
176
+ flex-shrink: 0;
177
+ }
178
+
179
+ /* ── dot grid ─────────────────────────────────────────────────────── */
180
+ .at-dots {
181
+ display: grid;
182
+ grid-template-columns: repeat(3, 4px);
183
+ gap: 2px;
184
+ flex-shrink: 0;
185
+ }
186
+ .agent-thinking--sm .at-dots {
187
+ grid-template-columns: repeat(3, 3px);
188
+ }
189
+ .at-dot {
190
+ aspect-ratio: 1;
191
+ border-radius: 1px;
192
+ background: currentColor;
193
+ opacity: var(--at-seed);
194
+ animation: at-comet-cell var(--at-period) linear infinite;
195
+ }
196
+ /* One lap: the head peaks at 0%/100% and the tail falls off over 30%,
197
+ floored at 0.12 (agentThinking.ts cometOpacity). */
198
+ @keyframes at-comet-cell {
199
+ 0% {
200
+ opacity: 1;
201
+ }
202
+ 10% {
203
+ opacity: 0.599;
204
+ }
205
+ 20% {
206
+ opacity: 0.289;
207
+ }
208
+ 30% {
209
+ opacity: 0.12;
210
+ }
211
+ 95% {
212
+ opacity: 0.12;
213
+ }
214
+ 100% {
215
+ opacity: 1;
216
+ }
217
+ }
218
+
219
+ /* ── stars ────────────────────────────────────────────────────────── */
220
+ .at-stars {
221
+ position: relative;
222
+ display: block;
223
+ flex-shrink: 0;
224
+ width: 1.3em;
225
+ height: 1.3em;
226
+ color: color-mix(in oklab, currentColor 80%, transparent);
227
+ }
228
+ .at-star {
229
+ position: absolute;
230
+ translate: -50% -50%;
231
+ transform: scale(0);
232
+ animation-name: at-star;
233
+ animation-timing-function: ease-in-out;
234
+ animation-iteration-count: infinite;
235
+ }
236
+ @keyframes at-star {
237
+ 0%,
238
+ 100% {
239
+ transform: scale(0);
240
+ opacity: 0;
241
+ }
242
+ 40% {
243
+ transform: scale(1);
244
+ opacity: 1;
245
+ }
246
+ 60% {
247
+ transform: scale(0.8);
248
+ opacity: 0.9;
249
+ }
250
+ }
251
+
252
+ /* ── infinity ─────────────────────────────────────────────────────── */
253
+ .at-infinity {
254
+ flex-shrink: 0;
255
+ width: 2em;
256
+ height: 1em;
257
+ /* the figure-eight spans x 9–47 of 56: pull the dead space back in */
258
+ margin: 0 -0.25em;
259
+ }
260
+ .at-comet {
261
+ animation: at-dash 1200ms linear infinite;
262
+ }
263
+ @keyframes at-dash {
264
+ to {
265
+ stroke-dashoffset: -100;
266
+ }
267
+ }
268
+
269
+ @media (prefers-reduced-motion: reduce) {
270
+ .at-dot,
271
+ .at-comet {
272
+ animation: none;
273
+ }
274
+ .at-star {
275
+ animation: none;
276
+ transform: none;
277
+ opacity: 0.7;
278
+ }
279
+ }
280
+ </style>
@@ -0,0 +1,22 @@
1
+ import { type AgentThinkingTone, type AgentThinkingVariant } from './agentThinking';
2
+ interface Props {
3
+ variant?: AgentThinkingVariant;
4
+ /** Status label, e.g. "Thinking" or "Searching the docs". */
5
+ label?: string;
6
+ /** Indicator + label tone. Defaults per variant (`stars` is subtle). */
7
+ tone?: AgentThinkingTone;
8
+ /** Travelling highlight across the label. */
9
+ shimmer?: boolean;
10
+ /** Elapsed time after the label. */
11
+ showTimer?: boolean;
12
+ /**
13
+ * When the work started (epoch ms, Date.now() basis). Defaults to mount
14
+ * time. Pass it when the row can re-mount so the timer keeps counting.
15
+ */
16
+ startedAt?: number;
17
+ size?: 'sm' | 'md';
18
+ class?: string;
19
+ }
20
+ declare const AgentThinking: import("svelte").Component<Props, {}, "">;
21
+ type AgentThinking = ReturnType<typeof AgentThinking>;
22
+ export default AgentThinking;
@@ -0,0 +1,265 @@
1
+ <!--
2
+ ComposerGlow — wraps a composer and, while `active`, orbits a band of light
3
+ around its rim: a crisp line leading, a small glow and a soft bloom bleeding
4
+ inward (clipped by the box). Flip `active` while awaiting a reply; the light
5
+ fades in/out instead of snapping.
6
+
7
+ MIT License — Copyright (c) 2026 Mertcan Dundar Esmergul (BoardUI)
8
+ Adapted from BoardUI's composer-loader.tsx: the rounded-rect perimeter math,
9
+ the pathLength=100 dash + CSS dashoffset lap, the per-layer "head trails the
10
+ tip by N px" phase, the three blur scales, SVG-native feGaussianBlur (WebKit
11
+ ignores CSS `filter` on SVG children) and the ResizeObserver that keeps the
12
+ viewBox equal to the px box so stroke widths stay true.
13
+ Changed for jatui: colours are theme tokens (info → primary → mid →
14
+ secondary → accent, midpoint via color-mix in oklch — no hex, no JS colour
15
+ parsing); the surface is --color-base-100 on the box radius; knobs trimmed
16
+ to active / speed / intensity / radius; the 14-copy taper is dropped; the
17
+ lap only runs while visible; and on data-motion="calm" or under
18
+ prefers-reduced-motion there is no frozen arc — the light is replaced by a
19
+ plain static focus-ring tint.
20
+
21
+ The wrapped composer must not paint its own background (the glow paints the
22
+ surface under it):
23
+
24
+ <ComposerGlow active={busy}>
25
+ <MessageInput {busy} onStop={stop} onsend={send} />
26
+ </ComposerGlow>
27
+ -->
28
+ <script lang="ts">
29
+ import { untrack, type Snippet } from 'svelte';
30
+
31
+ interface Props {
32
+ /** Show the light. Fades in/out. */
33
+ active?: boolean;
34
+ /** Seconds per lap. Default 4.5. */
35
+ speed?: number;
36
+ intensity?: 'subtle' | 'normal' | 'vivid';
37
+ /**
38
+ * Corner radius: px number or any CSS length. Default: the box radius
39
+ * (--jatui-radius-box → --radius-box).
40
+ */
41
+ radius?: number | string;
42
+ class?: string;
43
+ children: Snippet;
44
+ }
45
+
46
+ let {
47
+ active = false,
48
+ speed = 4.5,
49
+ intensity = 'normal',
50
+ radius,
51
+ class: className = '',
52
+ children
53
+ }: Props = $props();
54
+
55
+ const uid = $props.id();
56
+ const gid = `jatui-cg-${uid.replace(/[^a-zA-Z0-9]/g, '')}`;
57
+
58
+ const INTENSITY = {
59
+ subtle: { light: 0.45, bloom: 0.22 },
60
+ normal: { light: 0.7, bloom: 0.3 },
61
+ vivid: { light: 0.95, bloom: 0.42 }
62
+ } as const;
63
+ const level = $derived(INTENSITY[intensity] ?? INTENSITY.normal);
64
+
65
+ const cssRadius = $derived(
66
+ radius == null
67
+ ? 'var(--jatui-radius-box, var(--radius-box, 0.5rem))'
68
+ : typeof radius === 'number'
69
+ ? `${radius}px`
70
+ : radius
71
+ );
72
+
73
+ // ── Geometry (the px box, so stroke widths are true) ────────────────
74
+ let clipEl = $state<HTMLSpanElement | null>(null);
75
+ let box = $state({ w: 640, h: 52, r: 8 });
76
+
77
+ $effect(() => {
78
+ const el = clipEl;
79
+ if (!el || typeof ResizeObserver === 'undefined') return;
80
+ const measure = () => {
81
+ const w = Math.max(1, el.clientWidth);
82
+ const h = Math.max(1, el.clientHeight);
83
+ const raw = getComputedStyle(el).borderTopLeftRadius;
84
+ const n = parseFloat(raw);
85
+ const r = Number.isFinite(n) ? (raw.trim().endsWith('%') ? (n / 100) * h : n) : 8;
86
+ untrack(() => {
87
+ if (w !== box.w || h !== box.h || r !== box.r) box = { w, h, r };
88
+ });
89
+ };
90
+ measure();
91
+ const ro = new ResizeObserver(measure);
92
+ ro.observe(el);
93
+ return () => ro.disconnect();
94
+ });
95
+
96
+ // Band = 120° of the lap; soft layers are slightly shorter and their heads
97
+ // sit N px behind the crisp tip.
98
+ const BAND = (120 / 360) * 100;
99
+ const LINE = 2.5;
100
+ const BLOOM = 16;
101
+ const rx = $derived(Math.min(box.r, box.w / 2, box.h / 2));
102
+ // Rounded-rect perimeter: straight runs + four quarter arcs.
103
+ const perimeter = $derived(Math.max(1, 2 * (box.w + box.h) - 8 * rx + 2 * Math.PI * rx));
104
+
105
+ /** Animation delay putting a layer `backPx` behind the tip (negative = head start, no stall). */
106
+ function delayFor(len: number, backPx: number): string {
107
+ const phase = len - BAND + (backPx * 100) / perimeter; // path units behind
108
+ const frac = (((phase / 100) % 1) + 1) % 1;
109
+ return `${((frac - 1) * speed).toFixed(3)}s`;
110
+ }
111
+
112
+ const layers = $derived([
113
+ // wide bloom bleeding inward (outer half clipped by the box)
114
+ { width: BLOOM * 2, blur: 14, opacity: level.bloom, len: BAND * 0.9, back: BLOOM + 16 },
115
+ // tight glow
116
+ { width: LINE * 3.2, blur: 6, opacity: 0.8, len: BAND * 0.95, back: 10 },
117
+ // crisp line, tip leading
118
+ { width: LINE, blur: 0.5, opacity: 1, len: BAND, back: 0 }
119
+ ]);
120
+
121
+ // Run the lap only while it can be seen: start on activate, stop after
122
+ // the fade-out has finished.
123
+ let running = $state(false);
124
+ $effect(() => {
125
+ if (active) {
126
+ running = true;
127
+ return;
128
+ }
129
+ const t = setTimeout(() => (running = false), 700);
130
+ return () => clearTimeout(t);
131
+ });
132
+ </script>
133
+
134
+ <div
135
+ class="composer-glow {className}"
136
+ class:composer-glow--active={active}
137
+ style:--cg-radius={cssRadius}
138
+ style:--cg-speed="{speed}s"
139
+ >
140
+ <span class="composer-glow-surface" aria-hidden="true"></span>
141
+ <span class="composer-glow-tint" aria-hidden="true"></span>
142
+ <span class="composer-glow-light" bind:this={clipEl} aria-hidden="true">
143
+ {#if running}
144
+ <svg
145
+ width="100%"
146
+ height="100%"
147
+ viewBox="0 0 {box.w} {box.h}"
148
+ preserveAspectRatio="none"
149
+ style:opacity={level.light}
150
+ >
151
+ <defs>
152
+ <linearGradient id={gid} x1="0" y1="0" x2="1" y2="0">
153
+ <stop offset="0%" style="stop-color: var(--color-info)" />
154
+ <stop offset="30%" style="stop-color: var(--color-primary)" />
155
+ <stop offset="50%" style="stop-color: color-mix(in oklch, var(--color-primary), var(--color-secondary))" />
156
+ <stop offset="70%" style="stop-color: var(--color-secondary)" />
157
+ <stop offset="100%" style="stop-color: var(--color-accent)" />
158
+ </linearGradient>
159
+ {#each layers as layer (layer.blur)}
160
+ <filter id="{gid}-b{String(layer.blur).replace('.', '_')}" x="-50%" y="-50%" width="200%" height="200%">
161
+ <feGaussianBlur stdDeviation={layer.blur} />
162
+ </filter>
163
+ {/each}
164
+ </defs>
165
+ {#each layers as layer (layer.blur)}
166
+ <rect
167
+ class="composer-glow-rect jatui-motion-ambient"
168
+ x="0"
169
+ y="0"
170
+ width={box.w}
171
+ height={box.h}
172
+ {rx}
173
+ pathLength="100"
174
+ fill="none"
175
+ stroke="url(#{gid})"
176
+ stroke-width={layer.width}
177
+ stroke-linecap="round"
178
+ stroke-dasharray="{layer.len} {100 - layer.len}"
179
+ filter="url(#{gid}-b{String(layer.blur).replace('.', '_')})"
180
+ style:opacity={layer.opacity}
181
+ style:animation-delay={delayFor(layer.len, layer.back)}
182
+ />
183
+ {/each}
184
+ </svg>
185
+ {/if}
186
+ </span>
187
+ <div class="composer-glow-content">{@render children()}</div>
188
+ </div>
189
+
190
+ <style>
191
+ .composer-glow {
192
+ position: relative;
193
+ border-radius: var(--cg-radius);
194
+ /* 1 = decorative motion allowed (motion.css); 0 on calm / reduced motion. */
195
+ --cg-ambient: var(--motion-ambient, 1);
196
+ --cg-fade: calc(var(--motion-move, 300ms) * 1.5);
197
+ }
198
+
199
+ .composer-glow-surface,
200
+ .composer-glow-tint,
201
+ .composer-glow-light {
202
+ position: absolute;
203
+ inset: 0;
204
+ border-radius: var(--cg-radius);
205
+ pointer-events: none;
206
+ }
207
+
208
+ .composer-glow-surface {
209
+ background: var(--color-base-100);
210
+ }
211
+
212
+ /* Calm / reduced-motion stand-in: a plain static focus-ring tint. */
213
+ .composer-glow-tint {
214
+ box-shadow:
215
+ 0 0 0 2px color-mix(in oklch, var(--color-primary) 30%, transparent),
216
+ inset 0 0 0 1px color-mix(in oklch, var(--color-primary) 45%, transparent);
217
+ opacity: 0;
218
+ transition: opacity var(--cg-fade) var(--motion-glide, ease);
219
+ }
220
+
221
+ .composer-glow-light {
222
+ overflow: hidden;
223
+ opacity: 0;
224
+ transition: opacity var(--cg-fade) var(--motion-glide, ease);
225
+ }
226
+
227
+ .composer-glow--active .composer-glow-light {
228
+ opacity: var(--cg-ambient);
229
+ }
230
+
231
+ .composer-glow--active .composer-glow-tint {
232
+ opacity: calc(1 - var(--cg-ambient));
233
+ }
234
+
235
+ .composer-glow-light svg {
236
+ display: block;
237
+ }
238
+
239
+ .composer-glow-rect {
240
+ animation: composer-glow-lap var(--cg-speed) linear infinite;
241
+ }
242
+
243
+ @keyframes composer-glow-lap {
244
+ from {
245
+ stroke-dashoffset: 0;
246
+ }
247
+ to {
248
+ stroke-dashoffset: -100;
249
+ }
250
+ }
251
+
252
+ .composer-glow-content {
253
+ position: relative;
254
+ }
255
+
256
+ /* Hosts without motion.css still get the reduced-motion swap. */
257
+ @media (prefers-reduced-motion: reduce) {
258
+ .composer-glow {
259
+ --cg-ambient: 0;
260
+ }
261
+ .composer-glow-rect {
262
+ animation: none;
263
+ }
264
+ }
265
+ </style>
@@ -0,0 +1,18 @@
1
+ import { type Snippet } from 'svelte';
2
+ interface Props {
3
+ /** Show the light. Fades in/out. */
4
+ active?: boolean;
5
+ /** Seconds per lap. Default 4.5. */
6
+ speed?: number;
7
+ intensity?: 'subtle' | 'normal' | 'vivid';
8
+ /**
9
+ * Corner radius: px number or any CSS length. Default: the box radius
10
+ * (--jatui-radius-box → --radius-box).
11
+ */
12
+ radius?: number | string;
13
+ class?: string;
14
+ children: Snippet;
15
+ }
16
+ declare const ComposerGlow: import("svelte").Component<Props, {}, "">;
17
+ type ComposerGlow = ReturnType<typeof ComposerGlow>;
18
+ export default ComposerGlow;