quassel 0.2.0 → 0.2.2
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/ChatMessages.d.ts +3 -1
- package/QuasselProvider.d.ts +10 -2
- package/README.md +4 -2
- package/chat.css +32 -35
- package/index.d.ts +1 -1
- package/index.js +41 -28
- package/index.js.map +3 -3
- package/package.json +1 -1
- package/texts.d.ts +0 -1
- package/ui/popover.d.ts +3 -1
package/ChatMessages.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { type ChatAppearance, type TimestampOptions, type CodeBlockOptions, type
|
|
|
7
7
|
* Der Verlauf: eigener Scroll-Container mit Autoscroll, solange man unten ist,
|
|
8
8
|
* und einem Zum-Ende-Knopf, sobald man liest. Ohne Eingabe read-only nutzbar.
|
|
9
9
|
*/
|
|
10
|
-
export declare function ChatMessages({ messages, owner, detailMode, running, working, stepsExpandable, texts, toolArgumentsText, renderTool, renderAction, onDismissAction, onLinkClick, emptyState, className, showTimestamps, announce, scrollerRef, maxWidth, horizontalPadding, jumpToEndThreshold, appearance, timestampOptions, codeBlockOptions, bubbleOptions, messageActions, }: {
|
|
10
|
+
export declare function ChatMessages({ messages, owner, detailMode, running, working, stepsExpandable, texts, toolArgumentsText, renderTool, renderAction, onDismissAction, onLinkClick, emptyState, className, scrollerClassName, showTimestamps, announce, scrollerRef, maxWidth, horizontalPadding, jumpToEndThreshold, appearance, timestampOptions, codeBlockOptions, bubbleOptions, messageActions, }: {
|
|
11
11
|
messages: Message[];
|
|
12
12
|
/** Beiträge mit diesem Message.sender erscheinen ohne Sprechblase; null behält die Nachrichtenvorgaben. */
|
|
13
13
|
owner?: string | null;
|
|
@@ -27,6 +27,8 @@ export declare function ChatMessages({ messages, owner, detailMode, running, wor
|
|
|
27
27
|
onLinkClick?: LinkClickHandler;
|
|
28
28
|
emptyState?: ReactNode;
|
|
29
29
|
className?: string;
|
|
30
|
+
/** Klassen des Hosts für den Scroll-Container (data-quassel-transcript). */
|
|
31
|
+
scrollerClassName?: string;
|
|
30
32
|
/** true = dezente HH:MM-Spalte links an jedem Block (Message.at). */
|
|
31
33
|
showTimestamps?: boolean;
|
|
32
34
|
/** Screenreader-Ansage fertiger Antworten und neuer Aktionen; false = der Host sagt selbst an. */
|
package/QuasselProvider.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ComponentType, type ReactNode } from "react";
|
|
1
|
+
import { type ComponentType, type ReactNode, type RefObject } from "react";
|
|
2
2
|
export type QuasselButtonVariant = "default" | "outline" | "secondary" | "ghost" | "destructive" | "link";
|
|
3
3
|
export type QuasselButtonSize = "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg";
|
|
4
4
|
export interface QuasselButtonProps {
|
|
@@ -45,6 +45,9 @@ export interface QuasselPopoverAnchor {
|
|
|
45
45
|
getBoundingClientRect: () => DOMRect;
|
|
46
46
|
contextElement?: Element;
|
|
47
47
|
}
|
|
48
|
+
/** Where popovers mount: an element, a ref or a getter; resolved when the popover opens. */
|
|
49
|
+
export type QuasselPortalTarget = HTMLElement | ShadowRoot;
|
|
50
|
+
export type QuasselPortalContainer = QuasselPortalTarget | RefObject<QuasselPortalTarget | null> | (() => QuasselPortalTarget | null | undefined);
|
|
48
51
|
export interface QuasselPopoverContentProps {
|
|
49
52
|
anchor?: QuasselPopoverAnchor;
|
|
50
53
|
align?: "start" | "center" | "end";
|
|
@@ -53,6 +56,8 @@ export interface QuasselPopoverContentProps {
|
|
|
53
56
|
collisionPadding?: number;
|
|
54
57
|
className?: string;
|
|
55
58
|
"aria-label"?: string;
|
|
59
|
+
/** The resolved portalContainer of QuasselProvider; undefined = document.body. */
|
|
60
|
+
portalContainer?: QuasselPortalTarget;
|
|
56
61
|
children?: ReactNode;
|
|
57
62
|
}
|
|
58
63
|
/** The primitives quassel renders; a host replaces any of them through QuasselProvider. */
|
|
@@ -65,12 +70,15 @@ export interface QuasselComponents {
|
|
|
65
70
|
PopoverContent: ComponentType<QuasselPopoverContentProps>;
|
|
66
71
|
}
|
|
67
72
|
export declare const defaultComponents: QuasselComponents;
|
|
68
|
-
export declare function QuasselProvider({ components, allowUrl, children }: {
|
|
73
|
+
export declare function QuasselProvider({ components, allowUrl, portalContainer, children }: {
|
|
69
74
|
/** Replaces single primitives; the rest stay the built-in ones or those of an outer provider. */
|
|
70
75
|
components?: Partial<QuasselComponents>;
|
|
71
76
|
/** Keeps Markdown link and image URLs that the default policy (http, https, mailto, tel, ftp, irc, xmpp, relative) would drop. */
|
|
72
77
|
allowUrl?: (url: string) => boolean;
|
|
78
|
+
/** Mounts quassel's popovers inside this element instead of document.body, e.g. within the host's theme wrapper. */
|
|
79
|
+
portalContainer?: QuasselPortalContainer;
|
|
73
80
|
children: ReactNode;
|
|
74
81
|
}): import("react").JSX.Element;
|
|
75
82
|
export declare const useQuasselComponents: () => QuasselComponents;
|
|
76
83
|
export declare const useAllowUrl: () => ((url: string) => boolean) | undefined;
|
|
84
|
+
export declare function useQuasselPortalContainer(): QuasselPortalTarget | undefined;
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Chat building blocks for React: a streaming transcript with thinking and tool st
|
|
|
4
4
|
actions, an input card with attachments and steering, and a small event contract that works
|
|
5
5
|
on the server as well. quassel is the chat of [RAgents](https://github.com/SchlenkR/RAgents),
|
|
6
6
|
published as a library. It ships a compiled stylesheet, so hosts need no Tailwind, and every
|
|
7
|
-
color, radius and font is a `--qsl-*` variable.
|
|
7
|
+
color, radius, font and font size is a `--qsl-*` variable.
|
|
8
8
|
|
|
9
9
|

|
|
10
10
|
|
|
@@ -27,7 +27,9 @@ rendering per action owner. Resolved actions stay in the transcript as a record.
|
|
|
27
27
|
</p>
|
|
28
28
|
|
|
29
29
|
**Your look, not a fork.** Override `--qsl-*` variables on any wrapper, switch light and dark
|
|
30
|
-
with `data-theme`, or hand quassel your own Button, Toggle, Card and Popover components.
|
|
30
|
+
with `data-theme`, or hand quassel your own Button, Toggle, Card and Popover components. With
|
|
31
|
+
`portalContainer` on `QuasselProvider`, popovers render inside your wrapper and pick up its
|
|
32
|
+
variables too.
|
|
31
33
|
|
|
32
34
|

|
|
33
35
|
|
package/chat.css
CHANGED
|
@@ -18,11 +18,12 @@
|
|
|
18
18
|
--qsl-font-weight-semibold: 600;
|
|
19
19
|
--qsl-leading-normal: 1.5;
|
|
20
20
|
--qsl-leading-relaxed: 1.625;
|
|
21
|
-
--qsl-radius-md: calc(var(--qsl-radius) * 0.8);
|
|
22
|
-
--qsl-radius-xl: calc(var(--qsl-radius) * 1.4);
|
|
23
21
|
--qsl-animate-spin: qsl-spin 1s linear infinite;
|
|
24
22
|
--qsl-default-transition-duration: 150ms;
|
|
25
23
|
--qsl-default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
24
|
+
--qsl-text-meta: 10.5px;
|
|
25
|
+
--qsl-text-trace: 11px;
|
|
26
|
+
--qsl-text-label: 0.72rem;
|
|
26
27
|
--qsl-radius-panel: 17px;
|
|
27
28
|
--qsl-animate-fade-pulse: qsl-fade-pulse 1.9s cubic-bezier(0.2, 0.6, 0.35, 1) infinite;
|
|
28
29
|
--qsl-animate-working-pulse: qsl-working-pulse 1.6s ease-in-out infinite;
|
|
@@ -405,32 +406,32 @@
|
|
|
405
406
|
.qsl\:overflow-y-auto {
|
|
406
407
|
overflow-y: auto;
|
|
407
408
|
}
|
|
408
|
-
.qsl\:rounded-\[
|
|
409
|
-
border-radius:
|
|
409
|
+
.qsl\:rounded-\[min\(--theme\(--radius-md\)\,10px\)\] {
|
|
410
|
+
border-radius: min(var(--qsl-radius-md, calc(var(--qsl-radius) * 0.8)), 10px);
|
|
410
411
|
}
|
|
411
|
-
.qsl\:rounded-\[min\(
|
|
412
|
-
border-radius: min(var(--qsl-radius-md),
|
|
412
|
+
.qsl\:rounded-\[min\(--theme\(--radius-md\)\,12px\)\] {
|
|
413
|
+
border-radius: min(var(--qsl-radius-md, calc(var(--qsl-radius) * 0.8)), 12px);
|
|
413
414
|
}
|
|
414
|
-
.qsl\:rounded-\[
|
|
415
|
-
border-radius:
|
|
415
|
+
.qsl\:rounded-\[var\(--qsl-bubble-radius\,10px_10px_4px_10px\)\] {
|
|
416
|
+
border-radius: var(--qsl-bubble-radius,10px 10px 4px 10px);
|
|
416
417
|
}
|
|
417
|
-
.qsl\:rounded-\[var\(--qsl-input-card-radius
|
|
418
|
-
border-radius: var(--qsl-input-card-radius,var(--qsl-radius-xl));
|
|
418
|
+
.qsl\:rounded-\[var\(--qsl-input-card-radius\,--theme\(--radius-xl\)\)\] {
|
|
419
|
+
border-radius: var(--qsl-input-card-radius,var(--qsl-radius-xl, calc(var(--qsl-radius) * 1.4)));
|
|
419
420
|
}
|
|
420
421
|
.qsl\:rounded-full {
|
|
421
422
|
border-radius: calc(infinity * 1px);
|
|
422
423
|
}
|
|
423
424
|
.qsl\:rounded-lg {
|
|
424
|
-
border-radius: var(--qsl-radius);
|
|
425
|
+
border-radius: var(--qsl-radius-lg, var(--qsl-radius));
|
|
425
426
|
}
|
|
426
427
|
.qsl\:rounded-md {
|
|
427
|
-
border-radius: calc(var(--qsl-radius) * 0.8);
|
|
428
|
+
border-radius: var(--qsl-radius-md, calc(var(--qsl-radius) * 0.8));
|
|
428
429
|
}
|
|
429
430
|
.qsl\:rounded-panel {
|
|
430
431
|
border-radius: var(--qsl-radius-panel);
|
|
431
432
|
}
|
|
432
433
|
.qsl\:rounded-sm {
|
|
433
|
-
border-radius: calc(var(--qsl-radius) * 0.6);
|
|
434
|
+
border-radius: var(--qsl-radius-sm, calc(var(--qsl-radius) * 0.6));
|
|
434
435
|
}
|
|
435
436
|
.qsl\:border {
|
|
436
437
|
border-style: var(--tw-border-style);
|
|
@@ -667,15 +668,6 @@
|
|
|
667
668
|
.qsl\:text-\[0\.8rem\] {
|
|
668
669
|
font-size: 0.8rem;
|
|
669
670
|
}
|
|
670
|
-
.qsl\:text-\[0\.72rem\] {
|
|
671
|
-
font-size: 0.72rem;
|
|
672
|
-
}
|
|
673
|
-
.qsl\:text-\[10\.5px\] {
|
|
674
|
-
font-size: 10.5px;
|
|
675
|
-
}
|
|
676
|
-
.qsl\:text-\[11px\] {
|
|
677
|
-
font-size: 11px;
|
|
678
|
-
}
|
|
679
671
|
.qsl\:text-\[13px\] {
|
|
680
672
|
font-size: 13px;
|
|
681
673
|
}
|
|
@@ -685,6 +677,15 @@
|
|
|
685
677
|
.qsl\:text-\[length\:var\(--qsl-chat-font-size\,13px\)\] {
|
|
686
678
|
font-size: var(--qsl-chat-font-size,13px);
|
|
687
679
|
}
|
|
680
|
+
.qsl\:text-label {
|
|
681
|
+
font-size: var(--qsl-text-label);
|
|
682
|
+
}
|
|
683
|
+
.qsl\:text-meta {
|
|
684
|
+
font-size: var(--qsl-text-meta);
|
|
685
|
+
}
|
|
686
|
+
.qsl\:text-trace {
|
|
687
|
+
font-size: var(--qsl-text-trace);
|
|
688
|
+
}
|
|
688
689
|
.qsl\:leading-\[1\.3\] {
|
|
689
690
|
--tw-leading: 1.3;
|
|
690
691
|
line-height: 1.3;
|
|
@@ -1071,13 +1072,13 @@
|
|
|
1071
1072
|
display: none;
|
|
1072
1073
|
}
|
|
1073
1074
|
:where([data-slot="button-group"]) .qsl\:in-data-\[slot\=button-group\]\:rounded-lg {
|
|
1074
|
-
border-radius: var(--qsl-radius);
|
|
1075
|
+
border-radius: var(--qsl-radius-lg, var(--qsl-radius));
|
|
1075
1076
|
}
|
|
1076
|
-
:where([data-tone="material"]) .qsl\:in-data-\[tone\=material\]\:rounded-\[9px\] {
|
|
1077
|
-
border-radius: 9px;
|
|
1077
|
+
:where([data-tone="material"]) .qsl\:in-data-\[tone\=material\]\:rounded-\[var\(--qsl-bubble-radius\,9px\)\] {
|
|
1078
|
+
border-radius: var(--qsl-bubble-radius,9px);
|
|
1078
1079
|
}
|
|
1079
1080
|
:where([data-tone="material"]) .qsl\:in-data-\[tone\=material\]\:rounded-xl {
|
|
1080
|
-
border-radius: calc(var(--qsl-radius) * 1.4);
|
|
1081
|
+
border-radius: var(--qsl-radius-xl, calc(var(--qsl-radius) * 1.4));
|
|
1081
1082
|
}
|
|
1082
1083
|
:where([data-tone="material"]) .qsl\:in-data-\[tone\=material\]\:border-glass-edge\/20 {
|
|
1083
1084
|
border-color: var(--qsl-glass-edge);
|
|
@@ -1512,12 +1513,12 @@
|
|
|
1512
1513
|
background-color: var(--qsl-border);
|
|
1513
1514
|
}
|
|
1514
1515
|
:is(.qsl\:\*\:\[img\:first-child\]\:rounded-t-xl > *):is(img:first-child) {
|
|
1515
|
-
border-top-left-radius: calc(var(--qsl-radius) * 1.4);
|
|
1516
|
-
border-top-right-radius: calc(var(--qsl-radius) * 1.4);
|
|
1516
|
+
border-top-left-radius: var(--qsl-radius-xl, calc(var(--qsl-radius) * 1.4));
|
|
1517
|
+
border-top-right-radius: var(--qsl-radius-xl, calc(var(--qsl-radius) * 1.4));
|
|
1517
1518
|
}
|
|
1518
1519
|
:is(.qsl\:\*\:\[img\:last-child\]\:rounded-b-xl > *):is(img:last-child) {
|
|
1519
|
-
border-bottom-right-radius: calc(var(--qsl-radius) * 1.4);
|
|
1520
|
-
border-bottom-left-radius: calc(var(--qsl-radius) * 1.4);
|
|
1520
|
+
border-bottom-right-radius: var(--qsl-radius-xl, calc(var(--qsl-radius) * 1.4));
|
|
1521
|
+
border-bottom-left-radius: var(--qsl-radius-xl, calc(var(--qsl-radius) * 1.4));
|
|
1521
1522
|
}
|
|
1522
1523
|
.qsl\:\[\&\>\*\:first-child\]\:mt-0 > :first-child {
|
|
1523
1524
|
margin-top: 0px;
|
|
@@ -1656,10 +1657,6 @@
|
|
|
1656
1657
|
--qsl-pop-shadow: 0 12px 36px #49384e26;
|
|
1657
1658
|
--qsl-card-shadow: 0 12px 22px #49384e2c;
|
|
1658
1659
|
}
|
|
1659
|
-
:where([data-quassel]) {
|
|
1660
|
-
--qsl-radius-md: calc(var(--qsl-radius) * 0.8);
|
|
1661
|
-
--qsl-radius-xl: calc(var(--qsl-radius) * 1.4);
|
|
1662
|
-
}
|
|
1663
1660
|
:where([data-theme="dark"]) {
|
|
1664
1661
|
--qsl-color-scheme: dark;
|
|
1665
1662
|
--qsl-background: #292735;
|
|
@@ -1750,7 +1747,7 @@
|
|
|
1750
1747
|
font-size: 1em;
|
|
1751
1748
|
}
|
|
1752
1749
|
:where([data-quassel], [data-quassel] *):where(small) {
|
|
1753
|
-
font-size: 80
|
|
1750
|
+
font-size: var(--qsl-text-small, 80%);
|
|
1754
1751
|
}
|
|
1755
1752
|
:where([data-quassel], [data-quassel] *):where(sub, sup) {
|
|
1756
1753
|
font-size: 75%;
|
package/index.d.ts
CHANGED
|
@@ -20,4 +20,4 @@ export { messageDate, timestampDay, timestampLabel } from "./timestamps";
|
|
|
20
20
|
export { attachmentCapabilityError, attachmentDownloadUrl, attachmentMediaType, encodeAttachment, formatAttachmentSize, validateAttachmentSelection, MAX_CHAT_ATTACHMENTS, MAX_CHAT_ATTACHMENT_BYTES, } from "./attachments";
|
|
21
21
|
export type { ChatAppearance, TimestampOptions, CodeBlockOptions, BubbleOptions, MessageAction, MessageActionsOptions, SendShortcut, } from "./options";
|
|
22
22
|
export { appearanceStyle } from "./options";
|
|
23
|
-
export { QuasselProvider, defaultComponents, useQuasselComponents, type QuasselComponents, type QuasselButtonProps, type QuasselButtonVariant, type QuasselButtonSize, type QuasselToggleProps, type QuasselCardProps, type QuasselStopButtonProps, type QuasselPopoverProps, type QuasselPopoverContentProps, type QuasselPopoverAnchor, } from "./QuasselProvider";
|
|
23
|
+
export { QuasselProvider, defaultComponents, useQuasselComponents, useQuasselPortalContainer, type QuasselComponents, type QuasselButtonProps, type QuasselButtonVariant, type QuasselButtonSize, type QuasselToggleProps, type QuasselCardProps, type QuasselStopButtonProps, type QuasselPopoverProps, type QuasselPopoverContentProps, type QuasselPopoverAnchor, type QuasselPortalContainer, type QuasselPortalTarget, } from "./QuasselProvider";
|
package/index.js
CHANGED
|
@@ -42,7 +42,6 @@ var defaultTexts = {
|
|
|
42
42
|
placeholder: "Nachricht schreiben ...",
|
|
43
43
|
steeringPlaceholder: "Dazwischenfunken ...",
|
|
44
44
|
steered: "In den laufenden Turn eingespeist",
|
|
45
|
-
inputHint: "Enter zum Senden - Shift + Enter f\xFCr eine neue Zeile",
|
|
46
45
|
detailModeTitle: "Detailgrad der Schritte",
|
|
47
46
|
detailModeOff: "nur Antworten",
|
|
48
47
|
detailModeCurrent: "aktuell",
|
|
@@ -87,7 +86,7 @@ var defaultTexts = {
|
|
|
87
86
|
|
|
88
87
|
// packages/quassel/src/ui/cn.ts
|
|
89
88
|
import { createCn } from "cn/config";
|
|
90
|
-
var cn = createCn({ prefix: "qsl" });
|
|
89
|
+
var cn = createCn({ prefix: "qsl", extend: { theme: { text: ["meta", "trace", "label"] } } });
|
|
91
90
|
|
|
92
91
|
// packages/quassel/src/ChatMessages.tsx
|
|
93
92
|
import { useCallback as useCallback2, useContext as useContext3, useEffect as useEffect3, useLayoutEffect, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
|
|
@@ -154,12 +153,12 @@ var buttonVariants = cva(
|
|
|
154
153
|
},
|
|
155
154
|
size: {
|
|
156
155
|
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",
|
|
157
|
-
xs: "qsl:h-6 qsl:gap-1 qsl:rounded-[min(
|
|
158
|
-
sm: "qsl:h-7 qsl:gap-1 qsl:rounded-[min(
|
|
156
|
+
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",
|
|
157
|
+
sm: "qsl:h-7 qsl:gap-1 qsl:rounded-[min(--theme(--radius-md),12px)] qsl:px-2.5 qsl:text-[0.8rem] 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",
|
|
159
158
|
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",
|
|
160
159
|
icon: "qsl:size-8",
|
|
161
|
-
"icon-xs": "qsl:size-6 qsl:rounded-[min(
|
|
162
|
-
"icon-sm": "qsl:size-7 qsl:rounded-[min(
|
|
160
|
+
"icon-xs": "qsl:size-6 qsl:rounded-[min(--theme(--radius-md),10px)] qsl:in-data-[slot=button-group]:rounded-lg qsl:[&_svg:not([class*='size-'])]:size-3",
|
|
161
|
+
"icon-sm": "qsl:size-7 qsl:rounded-[min(--theme(--radius-md),12px)] qsl:in-data-[slot=button-group]:rounded-lg",
|
|
163
162
|
"icon-lg": "qsl:size-9"
|
|
164
163
|
}
|
|
165
164
|
},
|
|
@@ -223,9 +222,10 @@ function PopoverContent({
|
|
|
223
222
|
anchor,
|
|
224
223
|
collisionPadding,
|
|
225
224
|
keepMounted,
|
|
225
|
+
portalContainer,
|
|
226
226
|
...props
|
|
227
227
|
}) {
|
|
228
|
-
return /* @__PURE__ */ jsx3(PopoverPrimitive.Portal, { keepMounted, children: /* @__PURE__ */ jsx3(
|
|
228
|
+
return /* @__PURE__ */ jsx3(PopoverPrimitive.Portal, { container: portalContainer, keepMounted, children: /* @__PURE__ */ jsx3(
|
|
229
229
|
PopoverPrimitive.Positioner,
|
|
230
230
|
{
|
|
231
231
|
align,
|
|
@@ -239,6 +239,7 @@ function PopoverContent({
|
|
|
239
239
|
PopoverPrimitive.Popup,
|
|
240
240
|
{
|
|
241
241
|
"data-quassel": "",
|
|
242
|
+
"data-quassel-popover": "",
|
|
242
243
|
"data-slot": "popover-content",
|
|
243
244
|
className: cn(
|
|
244
245
|
"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",
|
|
@@ -285,7 +286,7 @@ var toggleVariants = cva2(
|
|
|
285
286
|
},
|
|
286
287
|
size: {
|
|
287
288
|
default: "qsl:h-8 qsl:min-w-8 qsl:px-2.5 qsl:has-data-[icon=inline-end]:pr-2 qsl:has-data-[icon=inline-start]:pl-2",
|
|
288
|
-
sm: "qsl:h-7 qsl:min-w-7 qsl:rounded-[min(
|
|
289
|
+
sm: "qsl:h-7 qsl:min-w-7 qsl:rounded-[min(--theme(--radius-md),12px)] qsl:px-2.5 qsl:text-[0.8rem] 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",
|
|
289
290
|
lg: "qsl:h-9 qsl:min-w-9 qsl:px-2.5 qsl:has-data-[icon=inline-end]:pr-2 qsl:has-data-[icon=inline-start]:pl-2"
|
|
290
291
|
}
|
|
291
292
|
},
|
|
@@ -316,16 +317,22 @@ function Toggle({
|
|
|
316
317
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
317
318
|
var defaultComponents = { Button, Toggle, Card, StopButton, Popover, PopoverContent };
|
|
318
319
|
var QuasselContext = createContext({ components: defaultComponents });
|
|
319
|
-
function QuasselProvider({ components: components2, allowUrl, children }) {
|
|
320
|
+
function QuasselProvider({ components: components2, allowUrl, portalContainer, children }) {
|
|
320
321
|
const outer = useContext(QuasselContext);
|
|
321
322
|
const value = useMemo(() => ({
|
|
322
323
|
components: { ...outer.components, ...components2 },
|
|
323
|
-
allowUrl: allowUrl ?? outer.allowUrl
|
|
324
|
-
|
|
324
|
+
allowUrl: allowUrl ?? outer.allowUrl,
|
|
325
|
+
portalContainer: portalContainer ?? outer.portalContainer
|
|
326
|
+
}), [outer, components2, allowUrl, portalContainer]);
|
|
325
327
|
return /* @__PURE__ */ jsx7(QuasselContext.Provider, { value, children });
|
|
326
328
|
}
|
|
327
329
|
var useQuasselComponents = () => useContext(QuasselContext).components;
|
|
328
330
|
var useAllowUrl = () => useContext(QuasselContext).allowUrl;
|
|
331
|
+
function useQuasselPortalContainer() {
|
|
332
|
+
const container = useContext(QuasselContext).portalContainer;
|
|
333
|
+
const target = typeof container === "function" ? container() : container && "current" in container ? container.current : container;
|
|
334
|
+
return target ?? void 0;
|
|
335
|
+
}
|
|
329
336
|
|
|
330
337
|
// packages/quassel/src/useChatAction.ts
|
|
331
338
|
import { useEffect, useRef, useState } from "react";
|
|
@@ -506,7 +513,7 @@ function isTableDivider(line) {
|
|
|
506
513
|
import { useMemo as useMemo2 } from "react";
|
|
507
514
|
import { SparklesIcon, WrenchIcon, XIcon } from "lucide-react";
|
|
508
515
|
import { jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
509
|
-
var preClasses = "qsl:rounded-lg qsl:bg-secondary qsl:p-3 qsl:font-mono qsl:text-
|
|
516
|
+
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";
|
|
510
517
|
function StepPopover({
|
|
511
518
|
message,
|
|
512
519
|
position,
|
|
@@ -519,6 +526,7 @@ function StepPopover({
|
|
|
519
526
|
contextElement: document.documentElement
|
|
520
527
|
}), [position]);
|
|
521
528
|
const { Button: Button2, Popover: Popover2, PopoverContent: PopoverContent2 } = useQuasselComponents();
|
|
529
|
+
const portalContainer = useQuasselPortalContainer();
|
|
522
530
|
const tool = message.tool;
|
|
523
531
|
const thinking = message.role === "thinking";
|
|
524
532
|
const title = thinking ? texts.thinkingTitle : texts.toolTitle;
|
|
@@ -531,10 +539,11 @@ function StepPopover({
|
|
|
531
539
|
anchor,
|
|
532
540
|
"aria-label": title,
|
|
533
541
|
className: cn(
|
|
534
|
-
"qsl:w-[min(680px,calc(100vw-32px))] qsl:gap-0 qsl:overflow-hidden qsl:p-0 qsl:text-[13px] qsl:shadow-pop",
|
|
542
|
+
"qsl:w-[min(680px,calc(100vw-32px))] qsl:gap-0 qsl:overflow-hidden qsl:p-0 qsl:text-[13px] qsl:leading-normal qsl:shadow-pop",
|
|
535
543
|
thinking ? "qsl:max-h-none" : "qsl:max-h-[min(70vh,620px)]"
|
|
536
544
|
),
|
|
537
545
|
collisionPadding: 16,
|
|
546
|
+
portalContainer,
|
|
538
547
|
side: "bottom",
|
|
539
548
|
sideOffset: 10,
|
|
540
549
|
children: [
|
|
@@ -554,13 +563,13 @@ function StepPopover({
|
|
|
554
563
|
}
|
|
555
564
|
function PopoverSection({ label, value, error = false }) {
|
|
556
565
|
return /* @__PURE__ */ jsxs2("section", { children: [
|
|
557
|
-
/* @__PURE__ */ jsx9("h3", { className: "qsl:mb-1.5 qsl:text-
|
|
566
|
+
/* @__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 }),
|
|
558
567
|
/* @__PURE__ */ jsx9("pre", { className: cn(preClasses, error && "qsl:text-destructive"), children: value })
|
|
559
568
|
] });
|
|
560
569
|
}
|
|
561
570
|
|
|
562
571
|
// packages/quassel/src/PendingActionCard.tsx
|
|
563
|
-
import { CheckIcon as CheckIcon2 } from "lucide-react";
|
|
572
|
+
import { CheckIcon as CheckIcon2, XIcon as XIcon2 } from "lucide-react";
|
|
564
573
|
import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
565
574
|
var cardClasses = "qsl:gap-2.5 qsl:bg-background qsl:px-3.5 qsl:text-sm";
|
|
566
575
|
var resultText = (result) => typeof result === "string" ? result : result === null || result === void 0 ? "" : JSON.stringify(result);
|
|
@@ -577,7 +586,7 @@ function PendingActionCard({
|
|
|
577
586
|
return /* @__PURE__ */ jsxs3(Card2, { className: cardClasses, size: "sm", children: [
|
|
578
587
|
/* @__PURE__ */ jsx10("div", { className: "qsl:leading-normal", children: text }),
|
|
579
588
|
/* @__PURE__ */ jsxs3("div", { className: "qsl:flex qsl:items-center qsl:gap-1.5 qsl:text-sm qsl:text-muted-foreground", "data-action": "resolved", children: [
|
|
580
|
-
/* @__PURE__ */ jsx10(CheckIcon2, { className: "qsl:text-success", size: 12 }),
|
|
589
|
+
action.status === "approved" ? /* @__PURE__ */ jsx10(CheckIcon2, { className: "qsl:text-success", size: 12 }) : /* @__PURE__ */ jsx10(XIcon2, { size: 12 }),
|
|
581
590
|
action.status === "approved" ? resultText(action.result) : dismissedLabel
|
|
582
591
|
] })
|
|
583
592
|
] });
|
|
@@ -1005,7 +1014,7 @@ function announce(text) {
|
|
|
1005
1014
|
import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1006
1015
|
var stepClasses = "qsl:mt-[var(--qsl-chat-message-gap,16px)]";
|
|
1007
1016
|
var denseStepClasses = "qsl:mt-[var(--qsl-chat-dense-message-gap,8px)]";
|
|
1008
|
-
var traceClasses = "qsl:flex qsl:w-full qsl:gap-2 qsl:pl-6 qsl:text-left qsl:text-
|
|
1017
|
+
var traceClasses = "qsl:flex qsl:w-full qsl:gap-2 qsl:pl-6 qsl:text-left qsl:text-trace qsl:leading-[1.375] qsl:text-muted-foreground";
|
|
1009
1018
|
var traceButtonClasses = "qsl:cursor-pointer qsl:rounded-md qsl:py-1 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";
|
|
1010
1019
|
var traceIconClasses = "qsl:mt-0.5 qsl:flex-none qsl:opacity-60";
|
|
1011
1020
|
var traceErrorIconClasses = "qsl:mt-0.5 qsl:flex-none qsl:text-destructive qsl:opacity-100";
|
|
@@ -1013,7 +1022,7 @@ var traceLineClasses = "qsl:min-w-0 qsl:self-baseline qsl:font-mono qsl:[overflo
|
|
|
1013
1022
|
var traceRunningClasses = "qsl:ml-1.5 qsl:opacity-60";
|
|
1014
1023
|
var chipClasses = cn(
|
|
1015
1024
|
"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",
|
|
1016
|
-
"qsl:font-mono qsl:text-
|
|
1025
|
+
"qsl:font-mono qsl:text-meta qsl:leading-[1.6] qsl:text-muted-foreground qsl:transition-colors",
|
|
1017
1026
|
"qsl:data-[state=running]:border-[color-mix(in_srgb,var(--qsl-primary)_40%,var(--qsl-border-soft))]",
|
|
1018
1027
|
"qsl:data-[state=thinking]:border-[color-mix(in_srgb,var(--qsl-primary)_40%,var(--qsl-border-soft))]",
|
|
1019
1028
|
"qsl:data-[state=error]:border-[color-mix(in_srgb,var(--qsl-destructive)_45%,var(--qsl-border-soft))]",
|
|
@@ -1044,6 +1053,7 @@ function ChatMessages({
|
|
|
1044
1053
|
onLinkClick,
|
|
1045
1054
|
emptyState,
|
|
1046
1055
|
className,
|
|
1056
|
+
scrollerClassName,
|
|
1047
1057
|
showTimestamps = false,
|
|
1048
1058
|
announce: announce2,
|
|
1049
1059
|
scrollerRef,
|
|
@@ -1153,7 +1163,7 @@ function ChatMessages({
|
|
|
1153
1163
|
);
|
|
1154
1164
|
const mitZeit = (inhalt, key, at, dicht = false) => showTimestamps ? /* @__PURE__ */ jsxs6("div", { className: cn("qsl:flex qsl:items-baseline qsl:gap-2", dicht ? denseStepClasses : stepClasses), children: [
|
|
1155
1165
|
/* @__PURE__ */ jsx13("time", { dateTime: messageDate(at)?.toISOString(), className: cn(
|
|
1156
|
-
"qsl:flex-none qsl:text-
|
|
1166
|
+
"qsl:flex-none qsl:text-meta qsl:tabular-nums qsl:text-muted-foreground qsl:opacity-85",
|
|
1157
1167
|
timestampOptions?.format && timestampOptions.format !== "time" ? "qsl:w-[clamp(60px,20%,120px)]" : "qsl:w-[34px]"
|
|
1158
1168
|
), children: messageDate(at) ? timestampLabel(messageDate(at), timestampOptions, now) : "" }),
|
|
1159
1169
|
/* @__PURE__ */ jsx13("div", { className: "qsl:min-w-0 qsl:flex-1 qsl:[&>*:first-child]:mt-0", children: inhalt })
|
|
@@ -1259,8 +1269,10 @@ function ChatMessages({
|
|
|
1259
1269
|
"qsl:[--qsl-fade-edge:calc(100%_-_var(--qsl-composer-height,0px))]",
|
|
1260
1270
|
"qsl:[-webkit-mask-image:linear-gradient(to_bottom,#000_calc(var(--qsl-fade-edge)_-_40px),transparent_calc(var(--qsl-fade-edge)_+_16px))]",
|
|
1261
1271
|
"qsl:[mask-image:linear-gradient(to_bottom,#000_calc(var(--qsl-fade-edge)_-_40px),transparent_calc(var(--qsl-fade-edge)_+_16px))]",
|
|
1262
|
-
"qsl:in-data-[tone=material]:p-0"
|
|
1272
|
+
"qsl:in-data-[tone=material]:p-0",
|
|
1273
|
+
scrollerClassName
|
|
1263
1274
|
),
|
|
1275
|
+
"data-quassel-transcript": "",
|
|
1264
1276
|
onScroll: pruefeEnde,
|
|
1265
1277
|
onWheel: (event) => {
|
|
1266
1278
|
if (!event.ctrlKey && event.deltaY < 0) pauseUp(event.currentTarget, event.target);
|
|
@@ -1508,9 +1520,9 @@ function Bubble({
|
|
|
1508
1520
|
/* @__PURE__ */ jsxs6("div", { className: "qsl:min-w-0 qsl:flex-1", children: [
|
|
1509
1521
|
/* @__PURE__ */ jsx13("div", { className: cn(traceLineClasses, thinking && "qsl:font-sans qsl:italic qsl:whitespace-pre-wrap"), children: zeile }),
|
|
1510
1522
|
tool && /* @__PURE__ */ jsxs6("div", { className: "qsl:mt-0.5 qsl:border-l-2 qsl:border-border-soft qsl:pl-2", children: [
|
|
1511
|
-
/* @__PURE__ */ jsx13("pre", { className: "qsl:mb-0.5 qsl:max-h-[208px] qsl:overflow-auto qsl:font-mono qsl:text-
|
|
1523
|
+
/* @__PURE__ */ jsx13("pre", { className: "qsl:mb-0.5 qsl:max-h-[208px] qsl:overflow-auto qsl:font-mono qsl:text-meta qsl:leading-[1.375] qsl:break-all qsl:whitespace-pre-wrap qsl:opacity-80", children: toolArgumentsText(tool) }),
|
|
1512
1524
|
tool.result !== void 0 && /* @__PURE__ */ jsx13("pre", { className: cn(
|
|
1513
|
-
"qsl:mb-0.5 qsl:max-h-[208px] qsl:overflow-auto qsl:font-mono qsl:text-
|
|
1525
|
+
"qsl:mb-0.5 qsl:max-h-[208px] qsl:overflow-auto qsl:font-mono qsl:text-meta qsl:leading-[1.375] qsl:break-all qsl:whitespace-pre-wrap qsl:opacity-80",
|
|
1514
1526
|
tool.isError && "qsl:text-destructive qsl:opacity-100"
|
|
1515
1527
|
), children: prettyJson(tool.result) })
|
|
1516
1528
|
] })
|
|
@@ -1545,12 +1557,12 @@ function Bubble({
|
|
|
1545
1557
|
const showSender = bubbleOptions?.showSender ?? (!!message.bubble?.label && !plain);
|
|
1546
1558
|
const content = /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1547
1559
|
showSender && sender && /* @__PURE__ */ jsx13("span", { className: cn(
|
|
1548
|
-
"qsl:mb-[5px] qsl:table qsl:text-
|
|
1560
|
+
"qsl:mb-[5px] qsl:table qsl:text-label qsl:leading-[1.45] qsl:font-semibold",
|
|
1549
1561
|
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]"
|
|
1550
1562
|
), "data-chat": "sender", children: sender }),
|
|
1551
1563
|
/* @__PURE__ */ jsx13(Markdown, { text: message.text, streaming: message.role === "assistant" && !message.closed }),
|
|
1552
1564
|
/* @__PURE__ */ jsx13(MessageAttachments, { label: texts.attachments, message }),
|
|
1553
|
-
message.steered && /* @__PURE__ */ jsx13("small", { className: "qsl:mt-1 qsl:block qsl:text-
|
|
1565
|
+
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 }),
|
|
1554
1566
|
/* @__PURE__ */ jsx13(MessageActions, { message, options: messageActions, texts })
|
|
1555
1567
|
] });
|
|
1556
1568
|
const cursor = message.role === "assistant" && message.textCursor ? JSON.stringify(message.textCursor) : void 0;
|
|
@@ -1565,7 +1577,7 @@ function Bubble({
|
|
|
1565
1577
|
children: /* @__PURE__ */ jsx13(
|
|
1566
1578
|
"div",
|
|
1567
1579
|
{
|
|
1568
|
-
className: cn(bubbleBodyClasses, "qsl:group", message.bubble ? "qsl:rounded-lg qsl:text-white qsl:[--qsl-scroll-cover:var(--qsl-primary)]" : "qsl:rounded-[10px_10px_4px_10px] qsl:border qsl:border-border qsl:bg-secondary qsl:text-foreground qsl:[--qsl-scroll-cover:var(--qsl-secondary)] qsl:in-data-[tone=material]:rounded-[9px] qsl:in-data-[tone=material]:border-glass-edge/20 qsl:in-data-[tone=material]:bg-primary/15 qsl:in-data-[tone=material]:text-foreground"),
|
|
1580
|
+
className: cn(bubbleBodyClasses, "qsl:group", message.bubble ? "qsl:rounded-lg qsl:text-white qsl:[--qsl-scroll-cover:var(--qsl-primary)]" : "qsl:rounded-[var(--qsl-bubble-radius,10px_10px_4px_10px)] qsl:border qsl:border-border qsl:bg-secondary qsl:text-foreground qsl:[--qsl-scroll-cover:var(--qsl-secondary)] qsl:in-data-[tone=material]:rounded-[var(--qsl-bubble-radius,9px)] qsl:in-data-[tone=material]:border-glass-edge/20 qsl:in-data-[tone=material]:bg-primary/15 qsl:in-data-[tone=material]:text-foreground"),
|
|
1569
1581
|
"data-tone": message.bubble ? "on-color" : void 0,
|
|
1570
1582
|
style: { background: message.bubble?.color, maxWidth: bubbleOptions?.maxWidth },
|
|
1571
1583
|
children: content
|
|
@@ -1650,7 +1662,7 @@ function ChatPanel({
|
|
|
1650
1662
|
}
|
|
1651
1663
|
|
|
1652
1664
|
// packages/quassel/src/ChatInputToolbar.tsx
|
|
1653
|
-
import { PaperclipIcon, SendIcon, XIcon as
|
|
1665
|
+
import { PaperclipIcon, SendIcon, XIcon as XIcon3 } from "lucide-react";
|
|
1654
1666
|
|
|
1655
1667
|
// packages/quassel/src/ui/useFileInput.ts
|
|
1656
1668
|
import { useRef as useRef5, useState as useState6 } from "react";
|
|
@@ -1851,7 +1863,7 @@ function ChatInputToolbar({
|
|
|
1851
1863
|
const inputRows = inline || toolbar ? 1 : rows;
|
|
1852
1864
|
const inputMaxRows = inline || toolbar ? 1 : maxRows;
|
|
1853
1865
|
const rootClasses = cn(
|
|
1854
|
-
"qsl:flex qsl:shrink-0 qsl:flex-col qsl:overflow-hidden qsl:rounded-[var(--qsl-input-card-radius
|
|
1866
|
+
"qsl:flex qsl:shrink-0 qsl:flex-col qsl:overflow-hidden qsl:rounded-[var(--qsl-input-card-radius,--theme(--radius-xl))] qsl:border qsl:border-border-strong qsl:bg-background qsl:shadow-bar qsl:transition-colors qsl:focus-within:border-primary",
|
|
1855
1867
|
"qsl:in-data-[tone=material]:rounded-xl qsl:in-data-[tone=material]:border-glass-edge/50 qsl:in-data-[tone=material]:bg-background",
|
|
1856
1868
|
toolbar && "qsl:h-full qsl:min-w-0 qsl:flex-row qsl:items-center qsl:rounded-lg qsl:data-[working=true]:animate-working-pulse qsl:data-[working=true]:border-primary qsl:motion-reduce:data-[working=true]:animate-none",
|
|
1857
1869
|
fileInput.dragging && "qsl:outline-2 qsl:outline-offset-[3px] qsl:outline-dashed qsl:outline-primary"
|
|
@@ -2041,7 +2053,7 @@ function ChatInputToolbar({
|
|
|
2041
2053
|
size: "icon-sm",
|
|
2042
2054
|
title: fillText(alleTexte.removeAttachment, { name: entry.file.name }),
|
|
2043
2055
|
variant: "outline",
|
|
2044
|
-
children: /* @__PURE__ */ jsx15(
|
|
2056
|
+
children: /* @__PURE__ */ jsx15(XIcon3, {})
|
|
2045
2057
|
}
|
|
2046
2058
|
)
|
|
2047
2059
|
] }, entry.id)) });
|
|
@@ -2291,6 +2303,7 @@ export {
|
|
|
2291
2303
|
timestampLabel,
|
|
2292
2304
|
useChatAction,
|
|
2293
2305
|
useQuasselComponents,
|
|
2306
|
+
useQuasselPortalContainer,
|
|
2294
2307
|
validateAttachmentSelection
|
|
2295
2308
|
};
|
|
2296
2309
|
//# sourceMappingURL=index.js.map
|