@schlenkr/quassel 0.5.5 → 0.6.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.
package/index.js CHANGED
@@ -164,7 +164,7 @@ var defaultTexts = englishTexts;
164
164
 
165
165
  // packages/quassel/src/ui/cn.ts
166
166
  import { createCn } from "cn/config";
167
- var cn = createCn({ prefix: "qsl", extend: { theme: { text: ["meta", "trace", "timestamp", "label", "chat"] } } });
167
+ var cn = createCn({ prefix: "qsl", extend: { theme: { text: ["body", "small"] } } });
168
168
 
169
169
  // packages/quassel/src/ChatMessages.tsx
170
170
  import { useCallback as useCallback2, useContext as useContext3, useEffect as useEffect3, useLayoutEffect, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
@@ -177,6 +177,8 @@ function createChatScroll(onFollowChange = () => {
177
177
  }, getThreshold = () => defaultJumpToEndThreshold) {
178
178
  const atEnd = (viewport) => viewport.scrollHeight - viewport.clientHeight - viewport.scrollTop <= getThreshold();
179
179
  let following = true;
180
+ let held = false;
181
+ let heldTop = 0;
180
182
  let lastTop = 0;
181
183
  let lastHeight = 0;
182
184
  let lastClientHeight = 0;
@@ -187,6 +189,7 @@ function createChatScroll(onFollowChange = () => {
187
189
  lastClientHeight = viewport.clientHeight;
188
190
  };
189
191
  const follow = (value) => {
192
+ if (value) held = false;
190
193
  if (following === value) return;
191
194
  following = value;
192
195
  onFollowChange(value);
@@ -194,19 +197,23 @@ function createChatScroll(onFollowChange = () => {
194
197
  const layout = (viewport, dragging = false) => {
195
198
  if (viewport.clientHeight <= 0) return;
196
199
  if (movedUp(viewport, dragging) && !atEnd(viewport)) follow(false);
197
- if (atEnd(viewport)) follow(true);
200
+ if (viewport.scrollHeight <= viewport.clientHeight || atEnd(viewport) && !held) follow(true);
198
201
  if (following) viewport.scrollTop = Math.max(0, viewport.scrollHeight - viewport.clientHeight);
199
202
  remember(viewport);
200
203
  };
201
204
  return {
202
205
  layout,
203
206
  pause(viewport) {
204
- if (viewport.clientHeight > 0) follow(atEnd(viewport));
207
+ if (viewport.clientHeight <= 0 || viewport.scrollHeight <= viewport.clientHeight) return;
208
+ follow(false);
209
+ held = true;
210
+ heldTop = viewport.scrollTop;
205
211
  },
206
212
  scroll(viewport, dragging = false) {
207
213
  if (viewport.clientHeight <= 0) return;
208
- if (atEnd(viewport)) follow(true);
214
+ if (atEnd(viewport) && (!held || viewport.scrollTop > heldTop)) follow(true);
209
215
  else if (movedUp(viewport, dragging) && !atEnd(viewport)) follow(false);
216
+ heldTop = viewport.scrollTop;
210
217
  remember(viewport);
211
218
  },
212
219
  jump(viewport) {
@@ -229,7 +236,7 @@ import { Button as ButtonPrimitive } from "@base-ui/react/button";
229
236
  import { cva } from "class-variance-authority";
230
237
  import { jsx } from "react/jsx-runtime";
231
238
  var buttonVariants = cva(
232
- "qsl:group/button qsl:inline-flex qsl:shrink-0 qsl:items-center qsl:justify-center qsl:rounded-lg qsl:border qsl:border-transparent qsl:bg-clip-padding qsl:text-sm qsl:font-medium qsl:whitespace-nowrap qsl:transition-all qsl:outline-none qsl:select-none qsl:focus-visible:border-ring qsl:focus-visible:ring-3 qsl:focus-visible:ring-ring/50 qsl:active:not-aria-[haspopup]:translate-y-px qsl:disabled:pointer-events-none qsl:disabled:opacity-50 qsl:aria-invalid:border-destructive qsl:aria-invalid:ring-3 qsl:aria-invalid:ring-destructive/20 qsl:dark:aria-invalid:border-destructive/50 qsl:dark:aria-invalid:ring-destructive/40 qsl:[&_svg]:pointer-events-none qsl:[&_svg]:shrink-0 qsl:[&_svg:not([class*='size-'])]:size-4",
239
+ "qsl:group/button qsl:inline-flex qsl:shrink-0 qsl:items-center qsl:justify-center qsl:rounded-lg qsl:border qsl:border-transparent qsl:bg-clip-padding qsl:text-body qsl:font-medium qsl:whitespace-nowrap qsl:transition-all qsl:outline-none qsl:select-none qsl:focus-visible:border-ring qsl:focus-visible:ring-3 qsl:focus-visible:ring-ring/50 qsl:active:not-aria-[haspopup]:translate-y-px qsl:disabled:pointer-events-none qsl:disabled:opacity-50 qsl:aria-invalid:border-destructive qsl:aria-invalid:ring-3 qsl:aria-invalid:ring-destructive/20 qsl:dark:aria-invalid:border-destructive/50 qsl:dark:aria-invalid:ring-destructive/40 qsl:[&_svg]:pointer-events-none qsl:[&_svg]:shrink-0 qsl:[&_svg:not([class*='size-'])]:size-4",
233
240
  {
234
241
  variants: {
235
242
  variant: {
@@ -242,7 +249,7 @@ var buttonVariants = cva(
242
249
  },
243
250
  size: {
244
251
  default: "qsl:h-8 qsl:gap-1.5 qsl:px-2.5 qsl:has-data-[icon=inline-end]:pr-2 qsl:has-data-[icon=inline-start]:pl-2",
245
- xs: "qsl:h-6 qsl:gap-1 qsl:rounded-[min(--theme(--radius-md),10px)] qsl:px-2 qsl:text-xs qsl:in-data-[slot=button-group]:rounded-lg qsl:has-data-[icon=inline-end]:pr-1.5 qsl:has-data-[icon=inline-start]:pl-1.5 qsl:[&_svg:not([class*='size-'])]:size-3",
252
+ xs: "qsl:h-6 qsl:gap-1 qsl:rounded-[min(--theme(--radius-md),10px)] qsl:px-2 qsl:in-data-[slot=button-group]:rounded-lg qsl:has-data-[icon=inline-end]:pr-1.5 qsl:has-data-[icon=inline-start]:pl-1.5 qsl:[&_svg:not([class*='size-'])]:size-3",
246
253
  sm: "qsl:h-7 qsl:gap-1 qsl:rounded-[min(--theme(--radius-md),12px)] qsl:px-2.5 qsl:in-data-[slot=button-group]:rounded-lg qsl:has-data-[icon=inline-end]:pr-1.5 qsl:has-data-[icon=inline-start]:pl-1.5 qsl:[&_svg:not([class*='size-'])]:size-3.5",
247
254
  lg: "qsl:h-9 qsl:gap-1.5 qsl:px-2.5 qsl:has-data-[icon=inline-end]:pr-2 qsl:has-data-[icon=inline-start]:pl-2",
248
255
  icon: "qsl:size-8",
@@ -288,7 +295,7 @@ function Card({
288
295
  "data-slot": "card",
289
296
  "data-size": size,
290
297
  className: cn(
291
- "qsl:group/card qsl:flex qsl:flex-col qsl:gap-(--qsl-card-spacing) qsl:overflow-hidden qsl:rounded-panel qsl:border qsl:border-border qsl:bg-card qsl:py-(--qsl-card-spacing) qsl:text-sm qsl:text-card-foreground qsl:shadow-bar qsl:[--qsl-card-spacing:--spacing(4)] qsl:has-data-[slot=card-footer]:pb-0 qsl:has-[>img:first-child]:pt-0 qsl:data-[size=sm]:[--qsl-card-spacing:--spacing(3)] qsl:data-[size=sm]:has-data-[slot=card-footer]:pb-0 qsl:*:[img:first-child]:rounded-t-xl qsl:*:[img:last-child]:rounded-b-xl",
298
+ "qsl:group/card qsl:flex qsl:flex-col qsl:gap-(--qsl-card-spacing) qsl:overflow-hidden qsl:rounded-panel qsl:border qsl:border-border qsl:bg-card qsl:py-(--qsl-card-spacing) qsl:text-body qsl:text-card-foreground qsl:shadow-bar qsl:[--qsl-card-spacing:--spacing(4)] qsl:has-data-[slot=card-footer]:pb-0 qsl:has-[>img:first-child]:pt-0 qsl:data-[size=sm]:[--qsl-card-spacing:--spacing(3)] qsl:data-[size=sm]:has-data-[slot=card-footer]:pb-0 qsl:*:[img:first-child]:rounded-t-xl qsl:*:[img:last-child]:rounded-b-xl",
292
299
  className
293
300
  ),
294
301
  ...props
@@ -317,6 +324,7 @@ function PopoverContent({
317
324
  return /* @__PURE__ */ jsx3(PopoverPrimitive.Portal, { container: portalContainer, keepMounted, children: /* @__PURE__ */ jsx3(
318
325
  PopoverPrimitive.Positioner,
319
326
  {
327
+ "data-quassel": "",
320
328
  align,
321
329
  alignOffset,
322
330
  anchor,
@@ -331,7 +339,7 @@ function PopoverContent({
331
339
  "data-quassel-popover": "",
332
340
  "data-slot": "popover-content",
333
341
  className: cn(
334
- "qsl:z-[110] qsl:flex qsl:w-72 qsl:origin-(--transform-origin) qsl:flex-col qsl:gap-2.5 qsl:rounded-lg qsl:bg-popover qsl:p-2.5 qsl:text-sm qsl:text-popover-foreground qsl:shadow-md qsl:ring-1 qsl:ring-foreground/10 qsl:outline-hidden qsl:duration-100 qsl:data-[side=bottom]:slide-in-from-top-2 qsl:data-[side=inline-end]:slide-in-from-left-2 qsl:data-[side=inline-start]:slide-in-from-right-2 qsl:data-[side=left]:slide-in-from-right-2 qsl:data-[side=right]:slide-in-from-left-2 qsl:data-[side=top]:slide-in-from-bottom-2 qsl:data-open:animate-in qsl:data-open:fade-in-0 qsl:data-open:zoom-in-95 qsl:data-closed:animate-out qsl:data-closed:fade-out-0 qsl:data-closed:zoom-out-95",
342
+ "qsl:z-[110] qsl:flex qsl:w-72 qsl:origin-(--transform-origin) qsl:flex-col qsl:gap-2.5 qsl:rounded-lg qsl:bg-popover qsl:p-2.5 qsl:text-small qsl:text-popover-foreground qsl:shadow-md qsl:ring-1 qsl:ring-foreground/10 qsl:outline-hidden qsl:duration-100 qsl:data-[side=bottom]:slide-in-from-top-2 qsl:data-[side=inline-end]:slide-in-from-left-2 qsl:data-[side=inline-start]:slide-in-from-right-2 qsl:data-[side=left]:slide-in-from-right-2 qsl:data-[side=right]:slide-in-from-left-2 qsl:data-[side=top]:slide-in-from-bottom-2 qsl:data-open:animate-in qsl:data-open:fade-in-0 qsl:data-open:zoom-in-95 qsl:data-closed:animate-out qsl:data-closed:fade-out-0 qsl:data-closed:zoom-out-95",
335
343
  className
336
344
  ),
337
345
  ...props
@@ -366,7 +374,7 @@ import { Toggle as TogglePrimitive } from "@base-ui/react/toggle";
366
374
  import { cva as cva2 } from "class-variance-authority";
367
375
  import { jsx as jsx6 } from "react/jsx-runtime";
368
376
  var toggleVariants = cva2(
369
- "qsl:group/toggle qsl:inline-flex qsl:items-center qsl:justify-center qsl:gap-1 qsl:rounded-lg qsl:text-sm qsl:font-medium qsl:whitespace-nowrap qsl:transition-all qsl:outline-none qsl:hover:bg-muted qsl:hover:text-foreground qsl:focus-visible:border-ring qsl:focus-visible:ring-[3px] qsl:focus-visible:ring-ring/50 qsl:disabled:pointer-events-none qsl:disabled:opacity-50 qsl:aria-invalid:border-destructive qsl:aria-invalid:ring-destructive/20 qsl:aria-pressed:bg-muted qsl:data-[state=on]:bg-muted qsl:dark:aria-invalid:ring-destructive/40 qsl:[&_svg]:pointer-events-none qsl:[&_svg]:shrink-0 qsl:[&_svg:not([class*='size-'])]:size-4",
377
+ "qsl:group/toggle qsl:inline-flex qsl:items-center qsl:justify-center qsl:gap-1 qsl:rounded-lg qsl:text-body qsl:font-medium qsl:whitespace-nowrap qsl:transition-all qsl:outline-none qsl:hover:bg-muted qsl:hover:text-foreground qsl:focus-visible:border-ring qsl:focus-visible:ring-[3px] qsl:focus-visible:ring-ring/50 qsl:disabled:pointer-events-none qsl:disabled:opacity-50 qsl:aria-invalid:border-destructive qsl:aria-invalid:ring-destructive/20 qsl:aria-pressed:bg-muted qsl:data-[state=on]:bg-muted qsl:dark:aria-invalid:ring-destructive/40 qsl:[&_svg]:pointer-events-none qsl:[&_svg]:shrink-0 qsl:[&_svg:not([class*='size-'])]:size-4",
370
378
  {
371
379
  variants: {
372
380
  variant: {
@@ -486,7 +494,7 @@ function CodeBlock({ children }) {
486
494
  {
487
495
  ref: code,
488
496
  "data-chat": "code-block",
489
- className: cn(scrollbar, "qsl:my-2 qsl:overflow-auto qsl:overscroll-contain qsl:rounded-lg qsl:bg-secondary qsl:px-3 qsl:py-2 qsl:font-mono qsl:text-[length:1em] qsl:leading-relaxed qsl:in-data-[tone=on-color]:bg-black/30 qsl:in-data-[tone=on-color]:text-inherit"),
497
+ className: cn(scrollbar, "qsl:overflow-auto qsl:overscroll-contain"),
490
498
  style: { maxHeight: options?.maxHeight, whiteSpace: options?.wrap ? "pre-wrap" : void 0, overflowWrap: options?.wrap ? "anywhere" : void 0 },
491
499
  children
492
500
  }
@@ -509,7 +517,7 @@ function CodeBlock({ children }) {
509
517
  children: action.status === "done" ? /* @__PURE__ */ jsx8(CheckIcon, {}) : /* @__PURE__ */ jsx8(CopyIcon, {})
510
518
  }
511
519
  ),
512
- action.error && /* @__PURE__ */ jsx8("p", { className: "qsl:text-sm qsl:text-destructive", role: "alert", children: action.error })
520
+ action.error && /* @__PURE__ */ jsx8("p", { className: "qsl:text-small qsl:text-destructive", role: "alert", children: action.error })
513
521
  ] });
514
522
  }
515
523
  function MarkdownLinks({ children, onLinkClick }) {
@@ -523,7 +531,6 @@ function MarkdownLink({ href, children }) {
523
531
  return /* @__PURE__ */ jsx8(
524
532
  "a",
525
533
  {
526
- className: "qsl:text-primary qsl:[text-underline-offset:2px] qsl:in-data-[tone=on-color]:text-inherit qsl:in-data-[tone=on-color]:underline",
527
534
  href,
528
535
  onClick: (event) => {
529
536
  if (href && onLinkClick?.(href, event.currentTarget.textContent ?? "")) {
@@ -538,34 +545,32 @@ function MarkdownLink({ href, children }) {
538
545
  }
539
546
  var scrollbar = "qsl:[scrollbar-width:thin] qsl:[&::-webkit-scrollbar]:block qsl:[&::-webkit-scrollbar]:h-2 qsl:[&::-webkit-scrollbar-thumb]:rounded-full qsl:[&::-webkit-scrollbar-thumb]:bg-border";
540
547
  var scrollCover = "qsl:bg-[linear-gradient(to_right,var(--qsl-scroll-cover,var(--qsl-background))_50%,transparent)_left/20px_100%_no-repeat_local,linear-gradient(to_left,var(--qsl-scroll-cover,var(--qsl-background))_50%,transparent)_right/20px_100%_no-repeat_local,linear-gradient(to_right,#00000047,transparent)_left/14px_100%_no-repeat_scroll,linear-gradient(to_left,#00000047,transparent)_right/14px_100%_no-repeat_scroll]";
541
- var headingClasses = "qsl:mt-3 qsl:mb-1 qsl:text-[length:1.1em] qsl:font-medium";
542
- var cellClasses = "qsl:max-w-[44ch] qsl:border qsl:border-border qsl:px-2 qsl:py-1 qsl:text-left qsl:align-top qsl:in-data-[tone=on-color]:border-white/35";
543
548
  var components = {
544
- h1: ({ children }) => /* @__PURE__ */ jsx8("h1", { className: "qsl:mt-3 qsl:mb-1 qsl:text-[length:1.2em] qsl:font-semibold", children }),
545
- h2: ({ children }) => /* @__PURE__ */ jsx8("h2", { className: headingClasses, children }),
546
- h3: ({ children }) => /* @__PURE__ */ jsx8("h3", { className: headingClasses, children }),
547
- h4: ({ children }) => /* @__PURE__ */ jsx8("h4", { className: "qsl:mt-2 qsl:mb-1 qsl:font-medium", children }),
548
- h5: ({ children }) => /* @__PURE__ */ jsx8("h5", { className: "qsl:mt-2 qsl:mb-1 qsl:font-medium", children }),
549
- h6: ({ children }) => /* @__PURE__ */ jsx8("h6", { className: "qsl:mt-2 qsl:mb-1 qsl:font-medium", children }),
550
- p: ({ children }) => /* @__PURE__ */ jsx8("p", { className: "qsl:[p+&]:mt-3", children }),
551
- ul: ({ children }) => /* @__PURE__ */ jsx8("ul", { className: "qsl:my-3 qsl:list-disc qsl:pl-6 qsl:[li>&]:my-0", children }),
552
- ol: ({ children }) => /* @__PURE__ */ jsx8("ol", { className: "qsl:my-3 qsl:list-decimal qsl:pl-6 qsl:[li>&]:my-0", children }),
553
- li: ({ children }) => /* @__PURE__ */ jsx8("li", { className: "qsl:[li+&]:mt-1 qsl:marker:text-muted-foreground qsl:in-data-[tone=on-color]:marker:text-inherit", children }),
554
- hr: () => /* @__PURE__ */ jsx8("hr", { className: "qsl:my-3 qsl:border-t qsl:border-border" }),
549
+ h1: ({ children }) => /* @__PURE__ */ jsx8("h1", { children }),
550
+ h2: ({ children }) => /* @__PURE__ */ jsx8("h2", { children }),
551
+ h3: ({ children }) => /* @__PURE__ */ jsx8("h3", { children }),
552
+ h4: ({ children }) => /* @__PURE__ */ jsx8("h4", { children }),
553
+ h5: ({ children }) => /* @__PURE__ */ jsx8("h5", { children }),
554
+ h6: ({ children }) => /* @__PURE__ */ jsx8("h6", { children }),
555
+ p: ({ children }) => /* @__PURE__ */ jsx8("p", { children }),
556
+ ul: ({ children }) => /* @__PURE__ */ jsx8("ul", { children }),
557
+ ol: ({ children }) => /* @__PURE__ */ jsx8("ol", { children }),
558
+ li: ({ children }) => /* @__PURE__ */ jsx8("li", { children }),
559
+ hr: () => /* @__PURE__ */ jsx8("hr", {}),
555
560
  img: ({ src, alt }) => /* @__PURE__ */ jsx8("img", { alt, className: "qsl:h-auto qsl:max-w-full", src: typeof src === "string" ? src : void 0 }),
556
- blockquote: ({ children }) => /* @__PURE__ */ jsx8("blockquote", { className: "qsl:my-1 qsl:border-l-2 qsl:border-border qsl:pl-3 qsl:text-muted-foreground qsl:in-data-[tone=on-color]:border-white/50 qsl:in-data-[tone=on-color]:text-inherit", children }),
557
- strong: ({ children }) => /* @__PURE__ */ jsx8("strong", { className: "qsl:font-medium", children }),
561
+ blockquote: ({ children }) => /* @__PURE__ */ jsx8("blockquote", { children }),
562
+ strong: ({ children }) => /* @__PURE__ */ jsx8("strong", { children }),
558
563
  em: ({ children }) => /* @__PURE__ */ jsx8("em", { children }),
559
564
  a: ({ href, children }) => /* @__PURE__ */ jsx8(MarkdownLink, { href, children }),
560
565
  pre: ({ children }) => /* @__PURE__ */ jsx8(CodeBlock, { children }),
561
- code: ({ children, className }) => /* @__PURE__ */ jsx8("code", { className: cn(className, "qsl:rounded-sm qsl:bg-secondary qsl:px-1 qsl:py-0.5 qsl:font-mono qsl:text-[length:1em] qsl:[overflow-wrap:anywhere] qsl:in-data-[tone=on-color]:bg-white/20 qsl:in-data-[tone=on-color]:text-inherit", "qsl:[pre>&]:bg-transparent qsl:[pre>&]:p-0"), children }),
566
+ code: ({ children, className }) => /* @__PURE__ */ jsx8("code", { className, children }),
562
567
  // Without max-content the table shrinks to the container and stacks letters.
563
- table: ({ children }) => /* @__PURE__ */ jsx8("div", { className: cn(scrollbar, scrollCover, "qsl:my-2 qsl:overflow-x-auto qsl:overscroll-x-contain"), children: /* @__PURE__ */ jsx8("table", { className: "qsl:w-max qsl:min-w-full qsl:border-collapse qsl:text-sm", children }) }),
568
+ table: ({ children }) => /* @__PURE__ */ jsx8("div", { className: cn(scrollbar, scrollCover, "qsl:overflow-x-auto qsl:overscroll-x-contain"), "data-quassel-table": "", children: /* @__PURE__ */ jsx8("table", { className: "qsl:w-max qsl:min-w-full qsl:border-collapse", children }) }),
564
569
  thead: ({ children }) => /* @__PURE__ */ jsx8("thead", { children }),
565
570
  tbody: ({ children }) => /* @__PURE__ */ jsx8("tbody", { children }),
566
571
  tr: ({ children }) => /* @__PURE__ */ jsx8("tr", { children }),
567
- th: ({ children }) => /* @__PURE__ */ jsx8("th", { className: cn(cellClasses, "qsl:bg-secondary qsl:font-medium qsl:in-data-[tone=on-color]:bg-white/15 qsl:in-data-[tone=on-color]:text-inherit"), children }),
568
- td: ({ children }) => /* @__PURE__ */ jsx8("td", { className: cellClasses, children })
572
+ th: ({ children }) => /* @__PURE__ */ jsx8("th", { children }),
573
+ td: ({ children }) => /* @__PURE__ */ jsx8("td", { children })
569
574
  };
570
575
  function transformUrl(url, allowUrl, resolveUrl) {
571
576
  const resolved = resolveUrl ? resolveUrl(url) : url;
@@ -577,10 +582,9 @@ function Markdown({ text, streaming = false }) {
577
582
  const allowUrl = useAllowUrl();
578
583
  const resolveUrl = useResolveUrl();
579
584
  const urlTransform = useCallback((url) => transformUrl(url, allowUrl, resolveUrl), [allowUrl, resolveUrl]);
580
- return /* @__PURE__ */ jsx8(
585
+ return /* @__PURE__ */ jsx8("div", { "data-quassel": "", "data-quassel-markdown": "", children: /* @__PURE__ */ jsx8(
581
586
  Streamdown,
582
587
  {
583
- className: "space-y-0 text-inherit",
584
588
  prefix: "qsl",
585
589
  mode: streaming ? "streaming" : "static",
586
590
  isAnimating: streaming,
@@ -592,7 +596,7 @@ function Markdown({ text, streaming = false }) {
592
596
  skipHtml: true,
593
597
  children: text
594
598
  }
595
- );
599
+ ) });
596
600
  }
597
601
  function markdownPlainText(text) {
598
602
  return text.split("\n").filter((line) => !/^\s*```\w*\s*$/.test(line) && !isTableDivider(line)).map((line) => (line.trim().startsWith("|") ? splitTableRow(line).join(", ") : line).replace(/^(#{1,6})\s+/, "").replace(/^\s*>\s?/, "").replace(/^\s*([-*+]|\d+[.)])\s+/, "").replace(/!?\[([^\]]*)\]\(([^)]+)\)|\*\*([^*]+)\*\*|__([^_]+)__|\*([^*]+)\*|`([^`]+)`/g, (_, link, _href, bold, boldUnderscore, italic, code) => link ?? bold ?? boldUnderscore ?? italic ?? code).trim()).filter((line) => line !== "").join("\n");
@@ -620,7 +624,7 @@ var stepPopoverOrigin = (event) => ({
620
624
  y: event.clientY,
621
625
  base: getComputedStyle(event.currentTarget).getPropertyValue("--qsl-base")
622
626
  });
623
- var preClasses = "qsl:rounded-lg qsl:bg-secondary qsl:p-3 qsl:font-mono qsl:text-trace qsl:leading-[1.625] qsl:break-all qsl:whitespace-pre-wrap";
627
+ var preClasses = "qsl:rounded-lg qsl:bg-secondary qsl:p-3 qsl:font-mono qsl:text-small qsl:break-all qsl:whitespace-pre-wrap";
624
628
  function StepPopover({
625
629
  message,
626
630
  position,
@@ -651,7 +655,7 @@ function StepPopover({
651
655
  anchor,
652
656
  "aria-label": title,
653
657
  className: cn(
654
- "qsl:w-[min(680px,calc(100vw-32px))] qsl:gap-0 qsl:overflow-hidden qsl:p-0 qsl:text-base qsl:leading-normal qsl:shadow-pop",
658
+ "qsl:w-[min(680px,calc(100vw-32px))] qsl:gap-0 qsl:overflow-hidden qsl:p-0 qsl:text-body qsl:shadow-pop",
655
659
  "qsl:max-h-[min(70dvh,620px,var(--available-height))]"
656
660
  ),
657
661
  collisionPadding: 16,
@@ -665,10 +669,10 @@ function StepPopover({
665
669
  /* @__PURE__ */ jsx9("span", { className: "qsl:min-w-0 qsl:flex-1 qsl:overflow-hidden qsl:text-ellipsis qsl:whitespace-nowrap qsl:font-medium", children: title }),
666
670
  /* @__PURE__ */ jsx9(Button2, { "aria-label": texts.close, className: "qsl:flex-none", onClick: onClose, size: "icon-sm", title: texts.close, variant: "ghost", children: /* @__PURE__ */ jsx9(XIcon, {}) })
667
671
  ] }),
668
- /* @__PURE__ */ jsx9("div", { className: "qsl:min-h-0 qsl:flex-1 qsl:overflow-auto qsl:overscroll-contain qsl:p-4", children: thinking ? /* @__PURE__ */ jsx9("div", { className: "qsl:text-sm qsl:leading-[1.625] qsl:whitespace-pre-wrap", children: message.text }) : tool ? /* @__PURE__ */ jsxs2("div", { className: "qsl:flex qsl:flex-col qsl:gap-4", children: [
669
- /* @__PURE__ */ jsx9("div", { className: "qsl:font-mono qsl:text-sm", children: message.text }),
672
+ /* @__PURE__ */ jsx9("div", { className: "qsl:min-h-0 qsl:flex-1 qsl:overflow-auto qsl:overscroll-contain qsl:p-4", children: thinking ? /* @__PURE__ */ jsx9("div", { className: "qsl:text-small qsl:whitespace-pre-wrap", children: message.text }) : tool ? /* @__PURE__ */ jsxs2("div", { className: "qsl:flex qsl:flex-col qsl:gap-4", children: [
673
+ /* @__PURE__ */ jsx9("div", { className: "qsl:font-mono qsl:text-small", children: message.text }),
670
674
  /* @__PURE__ */ jsx9(PopoverSection, { label: texts.argumentsLabel, value: toolArgumentsText(tool) }),
671
- tool.result === void 0 ? /* @__PURE__ */ jsx9("div", { className: "qsl:text-sm qsl:text-muted-foreground", children: texts.toolStillRunning }) : /* @__PURE__ */ jsx9(PopoverSection, { error: tool.isError, label: texts.resultLabel, value: prettyJson(tool.result) })
675
+ tool.result === void 0 ? /* @__PURE__ */ jsx9("div", { className: "qsl:text-small qsl:text-muted-foreground", children: texts.toolStillRunning }) : /* @__PURE__ */ jsx9(PopoverSection, { error: tool.isError, label: texts.resultLabel, value: prettyJson(tool.result) })
672
676
  ] }) : null })
673
677
  ]
674
678
  }
@@ -676,7 +680,7 @@ function StepPopover({
676
680
  }
677
681
  function PopoverSection({ label, value, error = false }) {
678
682
  return /* @__PURE__ */ jsxs2("section", { children: [
679
- /* @__PURE__ */ jsx9("h3", { className: "qsl:mb-1.5 qsl:text-trace qsl:font-semibold qsl:tracking-[0.04em] qsl:text-muted-foreground qsl:uppercase", children: label }),
683
+ /* @__PURE__ */ jsx9("h3", { className: "qsl:mb-1.5 qsl:text-small qsl:font-semibold qsl:tracking-[0.04em] qsl:text-muted-foreground qsl:uppercase", children: label }),
680
684
  /* @__PURE__ */ jsx9("pre", { className: cn(preClasses, error && "qsl:text-destructive"), children: value })
681
685
  ] });
682
686
  }
@@ -684,7 +688,7 @@ function PopoverSection({ label, value, error = false }) {
684
688
  // packages/quassel/src/PendingActionCard.tsx
685
689
  import { CheckIcon as CheckIcon2, XIcon as XIcon2 } from "lucide-react";
686
690
  import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
687
- var cardClasses = "qsl:gap-2.5 qsl:bg-background qsl:px-3.5 qsl:text-sm";
691
+ var cardClasses = "qsl:gap-2.5 qsl:bg-background qsl:px-3.5 qsl:text-body";
688
692
  var resultText = (result) => typeof result === "string" ? result : result === null || result === void 0 ? "" : JSON.stringify(result);
689
693
  function PendingActionCard({
690
694
  text,
@@ -697,17 +701,17 @@ function PendingActionCard({
697
701
  const { Button: Button2, Card: Card2 } = useQuasselComponents();
698
702
  if (action.status !== void 0) {
699
703
  return /* @__PURE__ */ jsxs3(Card2, { className: cardClasses, size: "sm", children: [
700
- /* @__PURE__ */ jsx10("div", { className: "qsl:leading-normal", children: text }),
701
- /* @__PURE__ */ jsxs3("div", { className: "qsl:flex qsl:items-center qsl:gap-1.5 qsl:text-sm qsl:text-muted-foreground", "data-action": "resolved", children: [
704
+ /* @__PURE__ */ jsx10("div", { className: "qsl:text-body", children: text }),
705
+ /* @__PURE__ */ jsxs3("div", { className: "qsl:flex qsl:items-center qsl:gap-1.5 qsl:text-body qsl:text-muted-foreground", "data-action": "resolved", children: [
702
706
  action.status === "approved" ? /* @__PURE__ */ jsx10(CheckIcon2, { className: "qsl:text-success", size: 12 }) : /* @__PURE__ */ jsx10(XIcon2, { size: 12 }),
703
707
  action.status === "approved" ? resultText(action.result) : dismissedLabel
704
708
  ] })
705
709
  ] });
706
710
  }
707
711
  return /* @__PURE__ */ jsxs3(Card2, { className: cardClasses, size: "sm", children: [
708
- /* @__PURE__ */ jsx10("div", { className: "qsl:leading-normal", children: text }),
712
+ /* @__PURE__ */ jsx10("div", { className: "qsl:text-body", children: text }),
709
713
  /* @__PURE__ */ jsxs3("div", { className: "qsl:flex qsl:items-center qsl:justify-between qsl:gap-2", children: [
710
- /* @__PURE__ */ jsx10("span", { className: "qsl:text-sm qsl:text-muted-foreground", "data-action": "waiting", children: waitingLabel }),
714
+ /* @__PURE__ */ jsx10("span", { className: "qsl:text-small qsl:text-muted-foreground", "data-action": "waiting", children: waitingLabel }),
711
715
  onDismiss && /* @__PURE__ */ jsx10(Button2, { onClick: onDismiss, size: "sm", variant: "outline", children: dismissLabel })
712
716
  ] })
713
717
  ] });
@@ -896,7 +900,7 @@ function WorkingScenes({ label = "Working ...", compact = false }) {
896
900
  return () => window.clearInterval(timer);
897
901
  }, [reducedMotion]);
898
902
  const frame = scene.draw(Math.floor(frameTick / scene.tick) + (scene.moving ? offset : 0));
899
- return /* @__PURE__ */ jsxs4("span", { "aria-label": label, className: cn("qsl:flex qsl:items-center qsl:gap-2.5 qsl:text-chat", compact ? "qsl:text-inherit" : "qsl:mt-4 qsl:text-foreground"), "data-chat": "working", role: "status", children: [
903
+ return /* @__PURE__ */ jsxs4("span", { "aria-label": label, className: cn("qsl:flex qsl:items-center qsl:gap-2.5 qsl:text-body", compact ? "qsl:text-inherit" : "qsl:mt-4 qsl:text-foreground"), "data-chat": "working", role: "status", children: [
900
904
  !compact && /* @__PURE__ */ jsx11("span", { "aria-hidden": "true", className: "qsl:text-muted-foreground qsl:opacity-70", children: ">" }),
901
905
  /* @__PURE__ */ jsx11("span", { "aria-hidden": "true", className: cn("qsl:inline-block qsl:flex-none qsl:font-mono qsl:[font-variant-ligatures:none]", compact ? "qsl:w-[2.4em] qsl:text-center" : "qsl:w-[15rem]"), children: /* @__PURE__ */ jsx11("span", { className: "qsl:tracking-[0.02em] qsl:whitespace-pre qsl:motion-reduce:opacity-60", children: typeof frame === "string" ? frame : frame.map((cell, index) => /* @__PURE__ */ jsx11("span", { className: "qsl:inline-block qsl:w-[1.35em] qsl:text-center", children: cell }, index)) }) }, scene.id)
902
906
  ] });
@@ -950,12 +954,8 @@ import { CheckIcon as CheckIcon4, ChevronDownIcon, ChevronRightIcon, ChevronUpIc
950
954
  // packages/quassel/src/options.ts
951
955
  var cssLength = (value) => typeof value === "number" ? `${value}px` : value;
952
956
  var appearanceStyle = (appearance) => ({
953
- "--qsl-font-size": cssLength(appearance?.fontSize),
954
- "--qsl-chat-font-size": cssLength(appearance?.fontSize),
955
- "--qsl-chat-line-height": appearance?.lineHeight,
956
957
  "--qsl-chat-message-gap": cssLength(appearance?.messageGap),
957
958
  "--qsl-chat-dense-message-gap": cssLength(appearance?.denseMessageGap),
958
- "--qsl-tool-font-scale": appearance?.toolFontScale,
959
959
  "--qsl-tool-group-gap": cssLength(appearance?.toolGroupGap),
960
960
  "--qsl-tool-row-padding": cssLength(appearance?.toolRowPadding)
961
961
  });
@@ -1103,7 +1103,7 @@ function MessageActions({ message, options, texts, contentRef, side = message.ro
1103
1103
  item.id
1104
1104
  );
1105
1105
  }) }),
1106
- action.error && /* @__PURE__ */ jsx12("p", { className: "qsl:mt-2 qsl:text-sm qsl:text-destructive", role: "alert", children: action.error })
1106
+ action.error && /* @__PURE__ */ jsx12("p", { className: "qsl:mt-2 qsl:text-small qsl:text-destructive", role: "alert", children: action.error })
1107
1107
  ] });
1108
1108
  }
1109
1109
 
@@ -1191,7 +1191,7 @@ function announce(text) {
1191
1191
  import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
1192
1192
  var stepClasses = "qsl:mt-[var(--qsl-chat-message-gap,10px)]";
1193
1193
  var denseStepClasses = "qsl:mt-[var(--qsl-chat-dense-message-gap,3px)]";
1194
- var traceClasses = "qsl:flex qsl:w-full qsl:gap-2 qsl:py-[var(--qsl-tool-row-padding,1px)] qsl:pl-6 qsl:text-left qsl:text-trace qsl:leading-[1.375] qsl:text-muted-foreground";
1194
+ var traceClasses = "qsl:flex qsl:w-full qsl:gap-2 qsl:py-[var(--qsl-tool-row-padding,1px)] qsl:pl-6 qsl:text-left qsl:text-small qsl:text-muted-foreground";
1195
1195
  var traceButtonClasses = "qsl:cursor-pointer qsl:rounded-md qsl:pr-2 qsl:transition-colors qsl:hover:bg-secondary qsl:hover:text-foreground qsl:focus-visible:bg-secondary qsl:focus-visible:text-foreground qsl:focus-visible:outline-none";
1196
1196
  var traceIconClasses = "qsl:mt-0.5 qsl:flex-none qsl:opacity-60";
1197
1197
  var traceErrorIconClasses = "qsl:mt-0.5 qsl:flex-none qsl:text-destructive qsl:opacity-100";
@@ -1202,7 +1202,7 @@ var rowErrorIconClasses = cn(traceErrorIconClasses, "qsl:mt-0");
1202
1202
  var rowLineClasses = cn(traceLineClasses, "qsl:self-auto");
1203
1203
  var chipClasses = cn(
1204
1204
  "qsl:inline-flex qsl:max-w-[220px] qsl:items-center qsl:gap-[5px] qsl:rounded-full qsl:border qsl:border-border-soft qsl:px-2.5 qsl:py-0.5",
1205
- "qsl:text-meta qsl:leading-[1.6] qsl:text-muted-foreground qsl:transition-colors",
1205
+ "qsl:text-small qsl:text-muted-foreground qsl:transition-colors",
1206
1206
  "qsl:data-[state=running]:border-[color-mix(in_srgb,var(--qsl-primary)_40%,var(--qsl-border-soft))]",
1207
1207
  "qsl:data-[state=thinking]:border-[color-mix(in_srgb,var(--qsl-primary)_40%,var(--qsl-border-soft))]",
1208
1208
  "qsl:data-[state=error]:border-[color-mix(in_srgb,var(--qsl-destructive)_45%,var(--qsl-border-soft))]",
@@ -1211,7 +1211,7 @@ var chipClasses = cn(
1211
1211
  var chipInteractiveClasses = "qsl:cursor-pointer qsl:hover:border-border qsl:hover:bg-secondary qsl:hover:text-foreground qsl:focus-visible:border-border qsl:focus-visible:bg-secondary qsl:focus-visible:text-foreground qsl:focus-visible:outline-none qsl:data-[state=done]:hover:opacity-100 qsl:data-[state=done]:focus-visible:opacity-100";
1212
1212
  var collapseAtBottomFrom = 11;
1213
1213
  var maxAnnouncementsAtOnce = 2;
1214
- var bubbleBodyClasses = "qsl:relative qsl:max-w-[86%] qsl:px-3 qsl:py-2 qsl:leading-[var(--qsl-chat-line-height,1.65)] qsl:[overflow-wrap:anywhere] qsl:@max-[620px]/chat:max-w-full";
1214
+ var bubbleBodyClasses = "qsl:relative qsl:max-w-[86%] qsl:px-3 qsl:py-2 qsl:text-body qsl:[overflow-wrap:anywhere] qsl:@max-[620px]/chat:max-w-full";
1215
1215
  function isStep(message) {
1216
1216
  return !!message && (message.role === "thinking" || message.role === "tool");
1217
1217
  }
@@ -1373,7 +1373,7 @@ function ChatMessages({
1373
1373
  "data-timestamp-position": timestampOptions?.position ?? "aside",
1374
1374
  children: [
1375
1375
  /* @__PURE__ */ jsx13("time", { dateTime: messageDate(at)?.toISOString(), className: cn(
1376
- "qsl:flex-none qsl:text-timestamp qsl:leading-[1.375] qsl:tabular-nums qsl:text-muted-foreground qsl:opacity-85",
1376
+ "qsl:flex-none qsl:text-small qsl:tabular-nums qsl:text-muted-foreground qsl:opacity-85",
1377
1377
  timestampOptions?.position === "above" ? "qsl:self-start" : timestampOptions?.format && timestampOptions.format !== "time" ? "qsl:w-[clamp(60px,20%,120px)]" : "qsl:min-w-[5ch] qsl:whitespace-nowrap"
1378
1378
  ), children: messageDate(at) ? timestampLabel(messageDate(at), timestampOptions, now) : "" }),
1379
1379
  /* @__PURE__ */ jsx13("div", { className: "qsl:min-w-0 qsl:flex-1 qsl:[&>*:first-child]:mt-0", children: content })
@@ -1428,7 +1428,7 @@ function ChatMessages({
1428
1428
  const day = timestampDay(date, timestampOptions);
1429
1429
  if (day.key !== lastDay) {
1430
1430
  closeGroup();
1431
- blocks.push(/* @__PURE__ */ jsx13("div", { className: cn(stepClasses, "qsl:text-center qsl:text-xs qsl:text-muted-foreground"), "data-chat": "day-separator", "data-day": day.key, children: day.label }, `day-${message.key}`));
1431
+ blocks.push(/* @__PURE__ */ jsx13("div", { className: cn(stepClasses, "qsl:text-center qsl:text-small qsl:text-muted-foreground"), "data-chat": "day-separator", "data-day": day.key, children: day.label }, `day-${message.key}`));
1432
1432
  lastDay = day.key;
1433
1433
  }
1434
1434
  }
@@ -1476,15 +1476,14 @@ function ChatMessages({
1476
1476
  const transcript = /* @__PURE__ */ jsxs6("div", { className: cn("qsl:@container/chat qsl:relative qsl:flex qsl:min-h-0 qsl:flex-1 qsl:flex-col", className), "data-quassel": "", style: {
1477
1477
  ...appearanceStyle(appearance),
1478
1478
  "--qsl-chat-content-max-width": typeof maxWidth === "number" ? `${maxWidth}px` : maxWidth,
1479
- "--qsl-chat-horizontal-padding": typeof horizontalPadding === "number" ? `${horizontalPadding}px` : horizontalPadding,
1480
- "--qsl-timestamp-font-size": timestampOptions?.fontScale === void 0 ? void 0 : `calc(var(--qsl-base) * ${timestampOptions.fontScale})`
1479
+ "--qsl-chat-horizontal-padding": typeof horizontalPadding === "number" ? `${horizontalPadding}px` : horizontalPadding
1481
1480
  }, children: [
1482
1481
  /* @__PURE__ */ jsx13(
1483
1482
  "div",
1484
1483
  {
1485
1484
  "aria-label": allTexts.transcript,
1486
1485
  className: cn(
1487
- "qsl:min-h-0 qsl:flex-1 qsl:cursor-default qsl:overflow-y-auto qsl:overscroll-contain qsl:text-chat qsl:text-foreground",
1486
+ "qsl:min-h-0 qsl:flex-1 qsl:cursor-default qsl:overflow-y-auto qsl:overscroll-contain qsl:text-body qsl:text-foreground",
1488
1487
  "qsl:[--qsl-fade-edge:calc(100%_-_var(--qsl-composer-height,0px))]",
1489
1488
  "qsl:[-webkit-mask-image:linear-gradient(to_bottom,#000_calc(var(--qsl-fade-edge)_-_40px),transparent_calc(var(--qsl-fade-edge)_+_16px))]",
1490
1489
  "qsl:[mask-image:linear-gradient(to_bottom,#000_calc(var(--qsl-fade-edge)_-_40px),transparent_calc(var(--qsl-fade-edge)_+_16px))]",
@@ -1542,7 +1541,7 @@ function ChatMessages({
1542
1541
  }
1543
1542
  }, children: /* @__PURE__ */ jsx13(ChevronDownIcon, {}) }) }),
1544
1543
  dock && openActions.length > 0 && createPortal(
1545
- /* @__PURE__ */ jsx13("div", { className: "qsl:flex qsl:flex-col qsl:gap-[var(--qsl-chat-dense-message-gap,3px)] qsl:text-chat qsl:text-foreground", style: appearanceStyle(appearance), children: openActions.map((message) => /* @__PURE__ */ jsx13("div", { children: /* @__PURE__ */ jsx13(ActionContent, { action: message.action, onDismissAction, renderAction, text: message.text, texts: allTexts }) }, message.key)) }),
1544
+ /* @__PURE__ */ jsx13("div", { className: "qsl:flex qsl:flex-col qsl:gap-[var(--qsl-chat-dense-message-gap,3px)] qsl:text-body qsl:text-foreground", style: appearanceStyle(appearance), children: openActions.map((message) => /* @__PURE__ */ jsx13("div", { children: /* @__PURE__ */ jsx13(ActionContent, { action: message.action, onDismissAction, renderAction, text: message.text, texts: allTexts }) }, message.key)) }),
1546
1545
  dock
1547
1546
  )
1548
1547
  ] });
@@ -1769,9 +1768,9 @@ function Bubble({
1769
1768
  /* @__PURE__ */ jsxs6("div", { className: "qsl:min-w-0 qsl:flex-1", children: [
1770
1769
  /* @__PURE__ */ jsx13("div", { className: cn(traceLineClasses, thinking && "qsl:italic qsl:whitespace-pre-wrap"), children: line }),
1771
1770
  tool && /* @__PURE__ */ jsxs6("div", { className: "qsl:mt-0.5 qsl:border-l-2 qsl:border-border-soft qsl:pl-2", children: [
1772
- /* @__PURE__ */ jsx13("pre", { className: "qsl:mb-0.5 qsl:max-h-[208px] qsl:overflow-auto qsl:overscroll-contain qsl:font-mono qsl:text-meta qsl:leading-[1.375] qsl:break-all qsl:whitespace-pre-wrap qsl:opacity-80", children: toolArgumentsText(tool) }),
1771
+ /* @__PURE__ */ jsx13("pre", { className: "qsl:mb-0.5 qsl:max-h-[208px] qsl:overflow-auto qsl:overscroll-contain qsl:font-mono qsl:text-small qsl:break-all qsl:whitespace-pre-wrap qsl:opacity-80", children: toolArgumentsText(tool) }),
1773
1772
  tool.result !== void 0 && /* @__PURE__ */ jsx13("pre", { className: cn(
1774
- "qsl:mb-0.5 qsl:max-h-[208px] qsl:overflow-auto qsl:overscroll-contain qsl:font-mono qsl:text-meta qsl:leading-[1.375] qsl:break-all qsl:whitespace-pre-wrap qsl:opacity-80",
1773
+ "qsl:mb-0.5 qsl:max-h-[208px] qsl:overflow-auto qsl:overscroll-contain qsl:font-mono qsl:text-small qsl:break-all qsl:whitespace-pre-wrap qsl:opacity-80",
1775
1774
  tool.isError && "qsl:text-destructive qsl:opacity-100"
1776
1775
  ), children: prettyJson(tool.result) })
1777
1776
  ] })
@@ -1782,7 +1781,7 @@ function Bubble({
1782
1781
  return /* @__PURE__ */ jsx13("div", { className: stepSpacing, children: /* @__PURE__ */ jsx13(ActionContent, { action: message.action, onDismissAction, renderAction, text: message.text, texts }) });
1783
1782
  }
1784
1783
  if (message.role === "system") {
1785
- return /* @__PURE__ */ jsxs6("div", { className: cn(stepSpacing, "qsl:border-l-2 qsl:border-destructive/50 qsl:pl-3 qsl:text-sm qsl:text-muted-foreground"), "data-message": "system", children: [
1784
+ return /* @__PURE__ */ jsxs6("div", { className: cn(stepSpacing, "qsl:border-l-2 qsl:border-destructive/50 qsl:pl-3 qsl:text-small qsl:text-muted-foreground"), "data-message": "system", children: [
1786
1785
  /* @__PURE__ */ jsx13(Markdown, { text: message.text }),
1787
1786
  /* @__PURE__ */ jsx13(MessageAttachments, { message, texts })
1788
1787
  ] });
@@ -1795,15 +1794,15 @@ function Bubble({
1795
1794
  const showSender = bubbleOptions?.showSender ?? (!!message.bubble?.label && !plain);
1796
1795
  const content = /* @__PURE__ */ jsxs6(Fragment2, { children: [
1797
1796
  showSender && sender && /* @__PURE__ */ jsx13("span", { className: cn(
1798
- "qsl:mb-[5px] qsl:table qsl:text-label qsl:leading-[1.45] qsl:font-semibold",
1797
+ "qsl:mb-[5px] qsl:table qsl:text-small qsl:font-semibold",
1799
1798
  useBubble && message.bubble && "qsl:rounded-full qsl:border qsl:border-white/30 qsl:bg-black/15 qsl:px-[7px] qsl:py-px qsl:tracking-[0.02em]"
1800
1799
  ), "data-chat": "sender", children: sender }),
1801
1800
  /* @__PURE__ */ jsx13("div", { "data-chat": "message-text", ref: textRef, children: /* @__PURE__ */ jsx13(Markdown, { text: message.text, streaming: message.role === "assistant" && !message.closed }) }),
1802
1801
  /* @__PURE__ */ jsx13(MessageAttachments, { message, texts }),
1803
- message.steered && /* @__PURE__ */ jsx13("small", { className: "qsl:mt-1 qsl:block qsl:text-label qsl:leading-[1.45] qsl:opacity-70", "data-chat": "steered", children: texts.steered })
1802
+ message.steered && /* @__PURE__ */ jsx13("small", { className: "qsl:mt-1 qsl:block qsl:text-small qsl:opacity-70", "data-chat": "steered", children: texts.steered })
1804
1803
  ] });
1805
1804
  const cursor = message.role === "assistant" && message.textCursor ? JSON.stringify(message.textCursor) : void 0;
1806
- if (!useBubble) return /* @__PURE__ */ jsxs6("div", { "data-chat-text-cursor": cursor, className: cn(stepSpacing, "qsl:group/message qsl:relative qsl:w-full qsl:leading-[var(--qsl-chat-line-height,1.65)] qsl:text-foreground"), "data-message": "answer", children: [
1805
+ if (!useBubble) return /* @__PURE__ */ jsxs6("div", { "data-chat-text-cursor": cursor, className: cn(stepSpacing, "qsl:group/message qsl:relative qsl:w-full qsl:text-foreground"), "data-message": "answer", children: [
1807
1806
  content,
1808
1807
  /* @__PURE__ */ jsx13(MessageActions, { contentRef: textRef, message, options: messageActions, side, texts })
1809
1808
  ] });
@@ -1861,7 +1860,7 @@ function MessageAttachments({ message, texts }) {
1861
1860
  return /* @__PURE__ */ jsxs6(Fragment2, { children: [
1862
1861
  /* @__PURE__ */ jsx13("ul", { className: "qsl:mt-2.5 qsl:flex qsl:flex-wrap qsl:gap-2", "aria-label": texts.attachments, children: message.attachments.map((attachment, index) => {
1863
1862
  const isImage = attachment.mediaType.startsWith("image/");
1864
- return /* @__PURE__ */ jsxs6("li", { className: cn("qsl:relative qsl:flex qsl:max-w-full qsl:min-w-0 qsl:flex-col qsl:overflow-hidden qsl:rounded-lg qsl:border qsl:border-border qsl:text-sm", isImage ? "qsl:w-[320px]" : "qsl:w-[190px]"), children: [
1863
+ return /* @__PURE__ */ jsxs6("li", { className: cn("qsl:relative qsl:flex qsl:max-w-full qsl:min-w-0 qsl:flex-col qsl:overflow-hidden qsl:rounded-lg qsl:border qsl:border-border qsl:text-small", isImage ? "qsl:w-[320px]" : "qsl:w-[190px]"), children: [
1865
1864
  isImage && /* @__PURE__ */ jsx13(
1866
1865
  "button",
1867
1866
  {
@@ -1896,7 +1895,7 @@ function ImageViewer({ attachment, onClose, texts }) {
1896
1895
  "data-chat": "image-viewer",
1897
1896
  children: attachment && /* @__PURE__ */ jsxs6(Fragment2, { children: [
1898
1897
  /* @__PURE__ */ jsx13("img", { className: "qsl:block qsl:max-h-[calc(100vh-6rem)] qsl:max-w-full qsl:rounded-md qsl:bg-background qsl:object-contain qsl:shadow-lg", src: attachment.url, alt: attachment.name }),
1899
- /* @__PURE__ */ jsxs6("div", { className: "qsl:flex qsl:items-center qsl:gap-4 qsl:text-sm qsl:text-white", children: [
1898
+ /* @__PURE__ */ jsxs6("div", { className: "qsl:flex qsl:items-center qsl:gap-4 qsl:text-small qsl:text-white", children: [
1900
1899
  /* @__PURE__ */ jsx13("span", { className: "qsl:[overflow-wrap:anywhere]", children: attachment.name }),
1901
1900
  /* @__PURE__ */ jsx13("a", { className: "qsl:underline", href: attachmentDownloadUrl(attachment.url), download: attachment.name, children: texts.downloadAttachment ?? defaultTexts.downloadAttachment }),
1902
1901
  /* @__PURE__ */ jsx13(Dialog.Close, { className: "qsl:cursor-pointer qsl:underline", children: texts.close })
@@ -2042,8 +2041,8 @@ import { useCallback as useCallback3, useContext as useContext4, useEffect as us
2042
2041
  import { createPortal as createPortal2 } from "react-dom";
2043
2042
  import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
2044
2043
  var COMPACT_WIDTH_PX = 480;
2045
- var errorClasses = "qsl:px-3 qsl:py-2 qsl:text-sm qsl:text-destructive";
2046
- var attachmentItemClasses = "qsl:relative qsl:flex qsl:w-[190px] qsl:max-w-full qsl:min-w-0 qsl:flex-col qsl:overflow-hidden qsl:rounded-lg qsl:border qsl:border-border qsl:text-sm";
2044
+ var errorClasses = "qsl:px-3 qsl:py-2 qsl:text-small qsl:text-destructive";
2045
+ var attachmentItemClasses = "qsl:relative qsl:flex qsl:w-[190px] qsl:max-w-full qsl:min-w-0 qsl:flex-col qsl:overflow-hidden qsl:rounded-lg qsl:border qsl:border-border qsl:text-small";
2047
2046
  var attachmentMediaClasses = "qsl:block qsl:h-[112px] qsl:w-full qsl:bg-secondary qsl:object-contain";
2048
2047
  function ChatInputToolbar({
2049
2048
  onSend,
@@ -2194,8 +2193,8 @@ function ChatInputToolbar({
2194
2193
  fileInput.dragging && "qsl:outline-2 qsl:outline-offset-[3px] qsl:outline-dashed qsl:outline-primary"
2195
2194
  );
2196
2195
  const textareaClasses = cn(
2197
- "qsl:resize-none qsl:overscroll-contain qsl:border-0 qsl:bg-transparent qsl:text-chat qsl:leading-[var(--qsl-chat-line-height,1.65)] qsl:text-foreground qsl:placeholder:text-muted-foreground qsl:focus:outline-none",
2198
- inline ? "qsl:min-w-0 qsl:flex-1 qsl:px-2.5 qsl:py-2" : toolbar ? "qsl:w-full qsl:min-w-0 qsl:flex-auto qsl:px-2 qsl:py-[3px] qsl:leading-[1.3]" : "qsl:px-3 qsl:pt-3 qsl:pb-2"
2196
+ "qsl:resize-none qsl:overscroll-contain qsl:border-0 qsl:bg-transparent qsl:text-body qsl:text-foreground qsl:placeholder:text-muted-foreground qsl:focus:outline-none",
2197
+ inline ? "qsl:min-w-0 qsl:flex-1 qsl:px-2.5 qsl:py-2" : toolbar ? "qsl:w-full qsl:min-w-0 qsl:flex-auto qsl:px-2 qsl:py-[3px]" : "qsl:px-3 qsl:pt-3 qsl:pb-2"
2199
2198
  );
2200
2199
  const toolbarRowClasses = cn(
2201
2200
  "qsl:flex qsl:items-center qsl:gap-2 qsl:border-t qsl:border-border-soft qsl:px-2 qsl:py-1.5 qsl:in-data-[tone=overseer-details]:flex-nowrap",
@@ -2250,7 +2249,7 @@ function ChatInputToolbar({
2250
2249
  return;
2251
2250
  }
2252
2251
  const style = getComputedStyle(element);
2253
- const lineHeight = Number.parseFloat(style.lineHeight) || Number.parseFloat(style.fontSize) * 1.4;
2252
+ const lineHeight = Number.parseFloat(style.lineHeight) || Number.parseFloat(style.fontSize) * 1.5;
2254
2253
  const padding = Number.parseFloat(style.paddingTop) + Number.parseFloat(style.paddingBottom);
2255
2254
  const maximum = lineHeight * Math.max(inputMaxRows, inputRows) + padding;
2256
2255
  element.style.height = "auto";
@@ -2442,7 +2441,7 @@ function ChatInputToolbar({
2442
2441
  children: /* @__PURE__ */ jsx15(PaperclipIcon, {})
2443
2442
  }
2444
2443
  ),
2445
- preparing && /* @__PURE__ */ jsx15("span", { className: cn("qsl:text-xs qsl:text-muted-foreground", inline && "qsl:sr-only"), role: "status", children: allTexts.attachmentsPreparing }),
2444
+ preparing && /* @__PURE__ */ jsx15("span", { className: cn("qsl:text-small qsl:text-muted-foreground", inline && "qsl:sr-only"), role: "status", children: allTexts.attachmentsPreparing }),
2446
2445
  actions?.map((action, index) => action.active === void 0 ? /* @__PURE__ */ jsxs8(Button2, { disabled: action.disabled, onClick: action.onClick, size: "sm", title: action.title ?? action.label, variant: "ghost", children: [
2447
2446
  action.icon,
2448
2447
  action.label && /* @__PURE__ */ jsx15("span", { className: action.icon ? "qsl:in-data-[compact=true]:hidden" : void 0, children: action.label })