@poodle64/librarian 2026.9.13 → 2026.9.15

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 (28) hide show
  1. package/README.md +77 -19
  2. package/dist/client.d.ts +16 -1
  3. package/dist/client.js +55 -8
  4. package/dist/components/activity-group/activity-group.svelte +76 -8
  5. package/dist/components/agent-transcript/agent-transcript.svelte +346 -150
  6. package/dist/components/agent-transcript/agent-transcript.svelte.d.ts +7 -0
  7. package/dist/components/artefact-card/artefact-card.svelte +30 -2
  8. package/dist/components/artefact-pane/artefact-pane.svelte +141 -50
  9. package/dist/components/composer/composer.svelte +255 -38
  10. package/dist/components/composer/composer.svelte.d.ts +6 -0
  11. package/dist/components/conversation/conversation.svelte +254 -81
  12. package/dist/components/conversation/conversation.svelte.d.ts +7 -0
  13. package/dist/components/document-pane/document-pane.svelte +216 -33
  14. package/dist/components/markdown/markdown.svelte +73 -24
  15. package/dist/components/scope-statement/scope-statement.svelte +79 -12
  16. package/dist/components/source-list/index.d.ts +2 -0
  17. package/dist/components/source-list/index.js +2 -0
  18. package/dist/components/source-list/source-list.svelte +137 -0
  19. package/dist/components/source-list/source-list.svelte.d.ts +13 -0
  20. package/dist/components/thinking-row/thinking-row.svelte +69 -18
  21. package/dist/components/tool-row/tool-row.svelte +132 -26
  22. package/dist/components/working/working.svelte +51 -7
  23. package/dist/components/working/working.svelte.d.ts +3 -0
  24. package/dist/copy.d.ts +45 -10
  25. package/dist/copy.js +77 -32
  26. package/dist/transcript.svelte.d.ts +10 -0
  27. package/dist/transcript.svelte.js +4 -1
  28. package/package.json +4 -2
@@ -3,9 +3,9 @@
3
3
 
4
4
  One element, two shapes. On a desktop it is a real column in the flow at
5
5
  about 40% of the width and draggable — the transcript narrows beside it and
6
- nothing is covered. Below `lg` there is no width to give it, so the same
6
+ nothing is covered. Under 64rem there is no width to give it, so the same
7
7
  element becomes a bottom sheet over the conversation. Two components would
8
- have meant two behaviours to keep honest; a class list is cheaper than that.
8
+ have meant two behaviours to keep honest; one media query is cheaper.
9
9
  -->
10
10
  <script lang="ts">
11
11
  import XIcon from '@lucide/svelte/icons/x';
@@ -118,76 +118,259 @@
118
118
 
119
119
  <svelte:window onkeydown={keydown} />
120
120
 
121
- <aside
122
- style="--pane-width: {width}px"
123
- aria-label="Source document"
124
- class="bg-surface-1 border-border fixed inset-x-0 bottom-0 z-40 flex h-[80svh] flex-col rounded-t-2xl border-t shadow-2xl lg:relative lg:h-auto lg:w-[var(--pane-width)] lg:shrink-0 lg:rounded-none lg:border-t-0 lg:border-l lg:shadow-none"
125
- >
126
- <!-- The drag handle. `lg:relative` on the pane above, not `lg:static`, is
127
- what this depends on: an absolutely-positioned child needs a positioned
128
- ancestor, and without one the handle lands somewhere else entirely and
129
- the pane is silently not resizable. Measured — the drag moved nothing. -->
121
+ <aside style="--ds-lib-pane-width: {width}px" aria-label="Source document" class="ds-lib-pane">
122
+ <!-- The drag handle. The pane being `position: relative` at 64rem, not
123
+ `static`, is what this depends on: an absolutely-positioned child needs
124
+ a positioned ancestor, and without one the handle lands somewhere else
125
+ entirely and the pane is silently not resizable. Measured — the drag
126
+ moved nothing. -->
130
127
  <!-- svelte-ignore a11y_no_static_element_interactions -- a pointer-only
131
128
  affordance for a width that has a keyboard-independent default; the
132
129
  pane is fully usable without ever touching it. -->
133
130
  <div
131
+ class="ds-lib-pane-handle"
134
132
  onpointerdown={startDrag}
135
133
  onpointermove={drag}
136
134
  onpointerup={endDrag}
137
- class="hover:bg-primary/40 absolute inset-y-0 left-0 hidden w-1.5 cursor-col-resize lg:block"
138
135
  ></div>
139
136
 
140
- <!-- The sheet's grabber. Below `lg` this is an overlay a reader has to be
137
+ <!-- The sheet's grabber. On a phone this is an overlay a reader has to be
141
138
  able to see the top edge of; on a desktop it is a column, and a column
142
139
  with a handle on it reads as draggable in the wrong axis. -->
143
- <div class="flex justify-center pt-2 pb-1 lg:hidden" aria-hidden="true">
144
- <span class="bg-border h-1 w-9 rounded-full"></span>
145
- </div>
140
+ <div class="ds-lib-pane-grabber" aria-hidden="true"><span></span></div>
146
141
 
147
- <header class="border-border flex items-start gap-2 border-b px-4 py-3 lg:pt-3">
148
- <div class="min-w-0 flex-1">
149
- <h2 class="text-foreground truncate text-sm font-semibold">
150
- {document_?.title ?? citation.title}
151
- </h2>
142
+ <header class="ds-lib-pane-header">
143
+ <div class="ds-lib-pane-heading">
144
+ <h2 class="ds-lib-pane-title">{document_?.title ?? citation.title}</h2>
152
145
  {#if citation.section}
153
- <p class="text-muted-foreground truncate text-xs">{citation.section}</p>
146
+ <p class="ds-lib-pane-subtitle">{citation.section}</p>
154
147
  {/if}
155
148
  {#if mark}
156
- <p class="text-muted-foreground/80 text-xs">{mark}</p>
149
+ <p class="ds-lib-pane-mark">{mark}</p>
157
150
  {/if}
158
151
  </div>
159
152
  <button
160
153
  bind:this={closeButton}
161
154
  type="button"
155
+ class="ds-lib-pane-close"
162
156
  onclick={onclose}
163
157
  aria-label={words.closeSource}
164
- class="text-muted-foreground hover:text-foreground hover:bg-surface-2 focus-visible:ring-ring -mt-1 flex size-8 shrink-0 items-center justify-center rounded-lg transition-colors focus-visible:ring-2 focus-visible:outline-none"
165
158
  >
166
- <XIcon class="size-4" />
159
+ <XIcon size={16} />
167
160
  </button>
168
161
  </header>
169
162
 
170
- <div bind:this={scroller} class="min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-3">
163
+ <div bind:this={scroller} class="ds-lib-pane-body">
171
164
  {#if failed}
172
- <p class="text-muted-foreground text-sm">{words.documentUnavailable}</p>
165
+ <p class="ds-lib-pane-failed">{words.documentUnavailable}</p>
173
166
  {:else if !document_}
174
- <div class="flex flex-col gap-2" aria-hidden="true">
167
+ <div class="ds-lib-pane-skeleton" aria-hidden="true">
175
168
  {#each [0, 1, 2, 3] as row (row)}
176
- <div class="bg-muted h-4 animate-pulse rounded" style="width: {90 - row * 12}%"></div>
169
+ <div class="ds-lib-pane-bar" style="width: {90 - row * 12}%"></div>
177
170
  {/each}
178
171
  </div>
179
172
  {:else}
180
173
  {#each document_.sections as section (section.anchor)}
181
174
  <section
182
175
  data-anchor={section.anchor}
183
- class="scroll-mt-4 rounded-lg px-3 py-2 {section.anchor === activeAnchor
184
- ? 'border-primary/50 bg-primary/8 border-l-2'
185
- : ''}"
176
+ class="ds-lib-pane-section"
177
+ class:is-cited={section.anchor === activeAnchor}
186
178
  >
187
- <h3 class="text-foreground mb-1 text-sm font-semibold">{section.heading}</h3>
179
+ <h3 class="ds-lib-pane-section-heading">{section.heading}</h3>
188
180
  <Markdown content={section.text} dense />
189
181
  </section>
190
182
  {/each}
191
183
  {/if}
192
184
  </div>
193
185
  </aside>
186
+
187
+ <style>
188
+ .ds-lib-pane {
189
+ position: fixed;
190
+ inset-inline: 0;
191
+ bottom: 0;
192
+ z-index: 40;
193
+ display: flex;
194
+ height: 80svh;
195
+ flex-direction: column;
196
+ border-top: 1px solid var(--ds-color-border);
197
+ border-start-start-radius: var(--ds-radius-xl);
198
+ border-start-end-radius: var(--ds-radius-xl);
199
+ background: var(--ds-color-surface-1);
200
+ box-shadow: 0 -12px 40px rgb(0 0 0 / 0.25);
201
+ }
202
+
203
+ .ds-lib-pane-handle {
204
+ display: none;
205
+ }
206
+
207
+ .ds-lib-pane-grabber {
208
+ display: flex;
209
+ justify-content: center;
210
+ padding-top: 0.5rem;
211
+ padding-bottom: 0.25rem;
212
+ }
213
+
214
+ .ds-lib-pane-grabber span {
215
+ width: 2.25rem;
216
+ height: 0.25rem;
217
+ border-radius: var(--ds-radius-full);
218
+ background: var(--ds-color-border);
219
+ }
220
+
221
+ .ds-lib-pane-header {
222
+ display: flex;
223
+ align-items: flex-start;
224
+ gap: 0.5rem;
225
+ border-bottom: 1px solid var(--ds-color-border);
226
+ padding: 0.75rem 1rem;
227
+ }
228
+
229
+ .ds-lib-pane-heading {
230
+ min-width: 0;
231
+ flex: 1;
232
+ }
233
+
234
+ .ds-lib-pane-title,
235
+ .ds-lib-pane-subtitle {
236
+ margin: 0;
237
+ overflow: hidden;
238
+ text-overflow: ellipsis;
239
+ white-space: nowrap;
240
+ }
241
+
242
+ .ds-lib-pane-title {
243
+ color: var(--ds-color-foreground);
244
+ font-family: inherit;
245
+ font-size: 0.875rem;
246
+ font-weight: 600;
247
+ }
248
+
249
+ .ds-lib-pane-subtitle {
250
+ color: var(--ds-color-muted-foreground);
251
+ font-size: var(--ds-text-2xs);
252
+ }
253
+
254
+ .ds-lib-pane-mark {
255
+ margin: 0;
256
+ color: color-mix(in oklab, var(--ds-color-muted-foreground) 80%, transparent);
257
+ font-size: var(--ds-text-2xs);
258
+ }
259
+
260
+ .ds-lib-pane-close {
261
+ display: flex;
262
+ width: 2rem;
263
+ height: 2rem;
264
+ flex: none;
265
+ align-items: center;
266
+ justify-content: center;
267
+ margin-top: -0.25rem;
268
+ border: 0;
269
+ border-radius: var(--ds-radius-lg);
270
+ background: none;
271
+ color: var(--ds-color-muted-foreground);
272
+ cursor: pointer;
273
+ transition:
274
+ color 150ms ease,
275
+ background-color 150ms ease;
276
+ }
277
+
278
+ .ds-lib-pane-close:hover {
279
+ background: var(--ds-color-surface-2);
280
+ color: var(--ds-color-foreground);
281
+ }
282
+
283
+ .ds-lib-pane-close:focus-visible {
284
+ outline: 2px solid var(--ds-color-ring);
285
+ outline-offset: 2px;
286
+ }
287
+
288
+ .ds-lib-pane-body {
289
+ min-height: 0;
290
+ flex: 1;
291
+ overflow-y: auto;
292
+ overscroll-behavior: contain;
293
+ padding: 0.75rem 1rem;
294
+ }
295
+
296
+ .ds-lib-pane-failed {
297
+ margin: 0;
298
+ color: var(--ds-color-muted-foreground);
299
+ font-size: 0.875rem;
300
+ }
301
+
302
+ .ds-lib-pane-skeleton {
303
+ display: flex;
304
+ flex-direction: column;
305
+ gap: 0.5rem;
306
+ }
307
+
308
+ .ds-lib-pane-bar {
309
+ height: 1rem;
310
+ border-radius: var(--ds-radius-md);
311
+ background: var(--ds-color-surface-2);
312
+ animation: ds-lib-pane-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
313
+ }
314
+
315
+ .ds-lib-pane-section {
316
+ scroll-margin-top: 1rem;
317
+ border-radius: var(--ds-radius-lg);
318
+ padding: 0.5rem 0.75rem;
319
+ }
320
+
321
+ .ds-lib-pane-section.is-cited {
322
+ border-inline-start: 2px solid color-mix(in oklab, var(--ds-color-primary) 50%, transparent);
323
+ background: color-mix(in oklab, var(--ds-color-primary) 8%, transparent);
324
+ }
325
+
326
+ .ds-lib-pane-section-heading {
327
+ margin: 0 0 0.25rem;
328
+ color: var(--ds-color-foreground);
329
+ font-family: inherit;
330
+ font-size: 0.875rem;
331
+ font-weight: 600;
332
+ }
333
+
334
+ @keyframes ds-lib-pane-pulse {
335
+ 50% {
336
+ opacity: 0.4;
337
+ }
338
+ }
339
+
340
+ @media (min-width: 64rem) {
341
+ .ds-lib-pane {
342
+ position: relative;
343
+ inset: auto;
344
+ height: auto;
345
+ width: var(--ds-lib-pane-width);
346
+ flex: none;
347
+ border-top: 0;
348
+ border-inline-start: 1px solid var(--ds-color-border);
349
+ border-radius: 0;
350
+ box-shadow: none;
351
+ }
352
+
353
+ .ds-lib-pane-handle {
354
+ position: absolute;
355
+ inset-block: 0;
356
+ inset-inline-start: 0;
357
+ display: block;
358
+ width: 0.375rem;
359
+ cursor: col-resize;
360
+ }
361
+
362
+ .ds-lib-pane-handle:hover {
363
+ background: color-mix(in oklab, var(--ds-color-primary) 40%, transparent);
364
+ }
365
+
366
+ .ds-lib-pane-grabber {
367
+ display: none;
368
+ }
369
+ }
370
+
371
+ @media (prefers-reduced-motion: reduce) {
372
+ .ds-lib-pane-bar {
373
+ animation: none;
374
+ }
375
+ }
376
+ </style>
@@ -74,13 +74,55 @@
74
74
  bind:this={host}
75
75
  onclick={click}
76
76
  onkeydown={keydown}
77
- class="agent-prose text-foreground {dense ? 'text-sm leading-6' : 'text-base leading-7'}"
77
+ class="agent-prose"
78
+ class:is-dense={dense}
79
+ class:is-streaming={streaming}
78
80
  >
79
81
  <!-- eslint-disable-next-line svelte/no-at-html-tags -- sanitised in render() -->
80
82
  {@html html}
81
83
  </div>
82
84
 
83
85
  <style>
86
+ .agent-prose {
87
+ color: var(--ds-color-foreground);
88
+ font-size: 1rem;
89
+ line-height: 1.75rem;
90
+ }
91
+
92
+ .agent-prose.is-dense {
93
+ font-size: 0.875rem;
94
+ line-height: 1.5rem;
95
+ }
96
+
97
+ /* The streaming caret. A pseudo-element on whatever block the text has
98
+ reached, rather than an element appended after the prose: injected into
99
+ the sanitiser's output it would fight every re-render, and placed after
100
+ the container it would sit on its own line under the paragraph being
101
+ written, which reads as a bullet rather than a cursor. */
102
+ .agent-prose.is-streaming :global(> *:last-child::after) {
103
+ content: '';
104
+ display: inline-block;
105
+ width: 0.45em;
106
+ height: 1.05em;
107
+ margin-inline-start: 0.12em;
108
+ border-radius: 1px;
109
+ background: var(--ds-color-primary);
110
+ vertical-align: -0.15em;
111
+ animation: ds-lib-caret 1.1s steps(1, end) infinite;
112
+ }
113
+
114
+ @keyframes ds-lib-caret {
115
+ 50% {
116
+ opacity: 0;
117
+ }
118
+ }
119
+
120
+ @media (prefers-reduced-motion: reduce) {
121
+ .agent-prose.is-streaming :global(> *:last-child::after) {
122
+ animation: none;
123
+ }
124
+ }
125
+
84
126
  .agent-prose :global(> *:first-child) {
85
127
  margin-top: 0;
86
128
  }
@@ -102,7 +144,7 @@
102
144
  .agent-prose :global(h2),
103
145
  .agent-prose :global(h3),
104
146
  .agent-prose :global(h4) {
105
- font-family: var(--ds-font-display, inherit);
147
+ font-family: var(--ds-font-display);
106
148
  font-weight: 600;
107
149
  line-height: 1.3;
108
150
  margin-block: 1.6em 0.6em;
@@ -112,7 +154,7 @@
112
154
  of the page (measured, both themes), so weight and rule do the work that
113
155
  a background tint cannot. */
114
156
  .agent-prose :global(h2) {
115
- border-top: 1px solid var(--border);
157
+ border-top: 1px solid var(--ds-color-border);
116
158
  padding-top: 0.8em;
117
159
  }
118
160
 
@@ -167,19 +209,19 @@
167
209
 
168
210
  .agent-prose :global(strong) {
169
211
  font-weight: 600;
170
- color: var(--foreground);
212
+ color: var(--ds-color-foreground);
171
213
  }
172
214
 
173
215
  .agent-prose :global(a) {
174
- color: var(--ds-color-primary, currentColor);
216
+ color: var(--ds-color-primary);
175
217
  text-underline-offset: 0.2em;
176
218
  text-decoration-line: underline;
177
219
  }
178
220
 
179
221
  .agent-prose :global(blockquote) {
180
- border-inline-start: 2px solid var(--primary);
222
+ border-inline-start: 2px solid var(--ds-color-primary);
181
223
  padding-inline: 1em 0;
182
- color: var(--muted-foreground);
224
+ color: var(--ds-color-muted-foreground);
183
225
  font-style: italic;
184
226
  }
185
227
 
@@ -196,10 +238,10 @@
196
238
  title is exactly the case: nowrap clipped it at the container edge on a
197
239
  phone with no way to read the rest. */
198
240
  .agent-prose :global(code) {
199
- font-family: var(--ds-font-mono, monospace);
241
+ font-family: var(--ds-font-code);
200
242
  font-size: 0.8125em;
201
- background: var(--muted);
202
- border: 1px solid var(--border);
243
+ background: var(--ds-color-surface-1);
244
+ border: 1px solid var(--ds-color-border);
203
245
  border-radius: 0.35em;
204
246
  padding: 0.1em 0.35em;
205
247
  white-space: normal;
@@ -207,9 +249,9 @@
207
249
  }
208
250
 
209
251
  .agent-prose :global(pre) {
210
- background: var(--muted);
211
- border: 1px solid var(--border);
212
- border-radius: var(--radius);
252
+ background: var(--ds-color-surface-1);
253
+ border: 1px solid var(--ds-color-border);
254
+ border-radius: var(--ds-radius-lg);
213
255
  padding: 0.85em 1em;
214
256
  overflow-x: auto;
215
257
  /* A fenced block is the one thing here allowed to be wider than the
@@ -250,7 +292,7 @@
250
292
 
251
293
  .agent-prose :global(th),
252
294
  .agent-prose :global(td) {
253
- border: 1px solid var(--border);
295
+ border: 1px solid var(--ds-color-border);
254
296
  padding: 0.4em 0.6em;
255
297
  text-align: start;
256
298
  /* A cell must not be squeezed to one character per line by a narrow
@@ -259,17 +301,24 @@
259
301
  }
260
302
 
261
303
  .agent-prose :global(th) {
262
- background: var(--muted);
304
+ background: var(--ds-color-surface-1);
263
305
  font-weight: 600;
264
306
  }
265
307
 
308
+ /* Zebra striping. A dense table of rates or dates is read across the row,
309
+ and at this palette's contrast a hairline grid alone is not enough to
310
+ keep an eye on one. */
311
+ .agent-prose :global(tbody tr:nth-child(even) td) {
312
+ background: color-mix(in oklab, var(--ds-color-surface-1) 45%, transparent);
313
+ }
314
+
266
315
  /* A collection reads as an entity rather than another monospace token when
267
316
  the caller passes `collectionNames`. Accent-tinted rather than the flat
268
317
  muted surface every other identifier sits on. */
269
318
  .agent-prose :global(code[data-collection]) {
270
- background: color-mix(in oklab, var(--primary) 16%, transparent);
271
- border-color: color-mix(in oklab, var(--primary) 45%, transparent);
272
- color: var(--foreground);
319
+ background: color-mix(in oklab, var(--ds-color-primary) 16%, transparent);
320
+ border-color: color-mix(in oklab, var(--ds-color-primary) 45%, transparent);
321
+ color: var(--ds-color-foreground);
273
322
  font-weight: 500;
274
323
  }
275
324
 
@@ -282,9 +331,9 @@
282
331
  margin-inline: 0.15em;
283
332
  padding: 0.1em 0.3em;
284
333
  border-radius: 0.4em;
285
- background: color-mix(in oklab, var(--primary) 16%, transparent);
286
- color: var(--foreground);
287
- font-family: var(--ds-font-mono, monospace);
334
+ background: color-mix(in oklab, var(--ds-color-primary) 16%, transparent);
335
+ color: var(--ds-color-foreground);
336
+ font-family: var(--ds-font-code);
288
337
  font-size: 0.7em;
289
338
  font-weight: 600;
290
339
  line-height: 1.4;
@@ -294,17 +343,17 @@
294
343
  }
295
344
 
296
345
  .agent-prose :global(sup.ds-cite:hover) {
297
- background: color-mix(in oklab, var(--primary) 30%, transparent);
346
+ background: color-mix(in oklab, var(--ds-color-primary) 30%, transparent);
298
347
  }
299
348
 
300
349
  .agent-prose :global(sup.ds-cite:focus-visible) {
301
- outline: 2px solid var(--ring);
350
+ outline: 2px solid var(--ds-color-ring);
302
351
  outline-offset: 2px;
303
352
  }
304
353
 
305
354
  .agent-prose :global(hr) {
306
355
  border: 0;
307
- border-top: 1px solid var(--border);
356
+ border-top: 1px solid var(--ds-color-border);
308
357
  margin-block: 1.5em;
309
358
  }
310
359
  </style>
@@ -1,5 +1,5 @@
1
1
  <!--
2
- What Milton answers from, and what he does not hold.
2
+ What this room answers from, and what it does not hold.
3
3
 
4
4
  A colleague's first question about a room is not the one they type — it is
5
5
  whether the answer they are about to read covers their case at all. Saying it
@@ -45,27 +45,94 @@
45
45
  });
46
46
  </script>
47
47
 
48
- <section
49
- class="border-border bg-surface-2/60 rounded-xl border px-3 py-2"
50
- aria-label={words.scope}
51
- >
48
+ <section class="ds-lib-scope" aria-label={words.scope}>
52
49
  <button
53
50
  type="button"
51
+ class="ds-lib-scope-toggle"
54
52
  onclick={() => (open = !open)}
55
53
  aria-expanded={open}
56
- class="text-muted-foreground hover:text-foreground focus-visible:ring-ring flex w-full items-center gap-2 rounded-md text-left text-xs transition-colors focus-visible:ring-2 focus-visible:outline-none"
57
54
  >
58
- <InfoIcon class="size-3.5 shrink-0" />
59
- <span class="min-w-0 flex-1 truncate font-medium tracking-wide uppercase">{words.scope}</span>
60
- <ChevronDownIcon class="size-3.5 shrink-0 transition-transform {open ? 'rotate-180' : ''}" />
55
+ <InfoIcon size={14} />
56
+ <span class="ds-lib-scope-label">{words.scope}</span>
57
+ <span class="ds-lib-scope-chevron" class:is-open={open}>
58
+ <ChevronDownIcon size={14} />
59
+ </span>
61
60
  </button>
62
61
 
63
62
  {#if open}
64
63
  <!-- No measure of its own: the card IS the measure, and a paragraph
65
64
  capped narrower than the border around it leaves a hand's width of
66
65
  empty card down the right at 1440. -->
67
- <p class="text-muted-foreground mt-1.5 text-sm leading-6 whitespace-pre-line">
68
- {statement}
69
- </p>
66
+ <p class="ds-lib-scope-text">{statement}</p>
70
67
  {/if}
71
68
  </section>
69
+
70
+ <style>
71
+ .ds-lib-scope {
72
+ border: 1px solid var(--ds-color-border);
73
+ border-radius: var(--ds-radius-xl);
74
+ background: color-mix(in oklab, var(--ds-color-surface-2) 60%, transparent);
75
+ padding: 0.5rem 0.75rem;
76
+ }
77
+
78
+ .ds-lib-scope-toggle {
79
+ display: flex;
80
+ width: 100%;
81
+ align-items: center;
82
+ gap: 0.5rem;
83
+ border: 0;
84
+ border-radius: var(--ds-radius-md);
85
+ background: none;
86
+ padding: 0;
87
+ color: var(--ds-color-muted-foreground);
88
+ font: inherit;
89
+ font-size: var(--ds-text-2xs);
90
+ text-align: start;
91
+ cursor: pointer;
92
+ transition: color 150ms ease;
93
+ }
94
+
95
+ .ds-lib-scope-toggle:hover {
96
+ color: var(--ds-color-foreground);
97
+ }
98
+
99
+ .ds-lib-scope-toggle:focus-visible {
100
+ outline: 2px solid var(--ds-color-ring);
101
+ outline-offset: 2px;
102
+ }
103
+
104
+ .ds-lib-scope-label {
105
+ min-width: 0;
106
+ flex: 1;
107
+ overflow: hidden;
108
+ text-overflow: ellipsis;
109
+ white-space: nowrap;
110
+ font-weight: 500;
111
+ letter-spacing: 0.05em;
112
+ text-transform: uppercase;
113
+ }
114
+
115
+ .ds-lib-scope-chevron {
116
+ display: flex;
117
+ flex: none;
118
+ transition: transform 150ms ease;
119
+ }
120
+
121
+ .ds-lib-scope-chevron.is-open {
122
+ transform: rotate(180deg);
123
+ }
124
+
125
+ .ds-lib-scope-text {
126
+ margin: 0.375rem 0 0;
127
+ color: var(--ds-color-muted-foreground);
128
+ font-size: 0.875rem;
129
+ line-height: 1.5rem;
130
+ white-space: pre-line;
131
+ }
132
+
133
+ @media (prefers-reduced-motion: reduce) {
134
+ .ds-lib-scope-chevron {
135
+ transition: none;
136
+ }
137
+ }
138
+ </style>
@@ -0,0 +1,2 @@
1
+ export { default } from './source-list.svelte';
2
+ export { default as SourceList } from './source-list.svelte';
@@ -0,0 +1,2 @@
1
+ export { default } from './source-list.svelte';
2
+ export { default as SourceList } from './source-list.svelte';