@cascivo/ai 0.2.12 → 0.2.14
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/dist/ai.css +2 -0
- package/dist/{index.d.mts → index.d.ts} +0 -8
- package/dist/index.js +188 -0
- package/dist/node/index.js +187 -0
- package/package.json +16 -9
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs +0 -222
- package/dist/index.mjs.map +0 -1
- package/dist/style.css +0 -217
package/dist/ai.css
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
@layer cascivo.component{._root_1vw7g_2{display:inline}._cursor_1vw7g_5{vertical-align:text-bottom;background:currentColor;width:2px;height:1em;margin-inline-start:1px;animation:1s step-end infinite _cascade-cursor-blink_1vw7g_1;display:inline-block}._root_5tg3n_2{align-items:center;gap:var(--cascivo-space-1);padding:var(--cascivo-space-1) var(--cascivo-space-2);border-radius:var(--cascivo-radius-indicator);font-size:var(--cascivo-font-size-xs);font-weight:500;line-height:1;display:inline-flex}._root_5tg3n_2[data-variant=generating]{background:var(--cascivo-color-surface-2);color:var(--cascivo-color-foreground-muted)}._root_5tg3n_2[data-variant=generating]:before{content:"";border-radius:var(--cascivo-radius-full);background:currentColor;block-size:.375rem;inline-size:.375rem;animation:1.5s ease-in-out infinite _cascade-ai-pulse_5tg3n_1}._root_5tg3n_2[data-variant=done]{background:var(--cascivo-color-success-subtle);color:var(--cascivo-color-success-foreground)}._root_5tg3n_2[data-variant=error]{background:var(--cascivo-color-destructive-subtle);color:var(--cascivo-color-destructive-foreground)}._root_1s9z8_2{color:oklch(90% .02 145);font-family:ui-monospace,Cascadia Code,Source Code Pro,monospace;font-size:var(--cascivo-font-size-sm,.875rem);padding:var(--cascivo-space-4);border-radius:var(--cascivo-radius-surface);background:oklch(12% .01 250);line-height:1.6;overflow-x:auto}._line_1s9z8_12{gap:var(--cascivo-space-2);display:flex}._prefix_1s9z8_16{color:oklch(70% .15 145);-webkit-user-select:none;user-select:none}._text_1s9z8_20{flex:1}._cursor_1s9z8_23{background:oklch(90% .02 145);width:8px;height:1em;animation:1s step-end infinite _cascade-cursor-blink_1s9z8_1;display:inline-block}._line_1s9z8_12[data-type=command] ._text_1s9z8_20{color:oklch(90% .1 250)}._line_1s9z8_12[data-type=error] ._text_1s9z8_20{color:oklch(75% .15 22)}._line_1s9z8_12[data-type=comment] ._text_1s9z8_20{color:oklch(60% .02 145)}._root_ilql2_2{background:var(--cascivo-color-background);border:1px solid var(--cascivo-border-default);border-radius:var(--cascivo-radius-surface);flex-direction:column;height:100%;min-height:400px;display:flex;overflow:hidden}._messages_ilql2_12{padding:var(--cascivo-space-4);gap:var(--cascivo-space-3);flex-direction:column;flex:1;display:flex;overflow-y:auto}._message_ilql2_12{gap:var(--cascivo-space-1);flex-direction:column;max-width:80%;display:flex}._message_ilql2_12[data-role=user]{align-self:flex-end;align-items:flex-end}._message_ilql2_12[data-role=assistant]{align-self:flex-start}._roleLabel_ilql2_33{font-size:var(--cascivo-font-size-xs,.75rem);color:var(--cascivo-color-foreground-muted);font-weight:500}._content_ilql2_38{padding:var(--cascivo-space-2) var(--cascivo-space-3);border-radius:var(--cascivo-radius-control);background:var(--cascivo-color-surface);line-height:1.5}._message_ilql2_12[data-role=user] ._content_ilql2_38{background:var(--cascivo-color-accent);color:var(--cascivo-color-accent-foreground)}._inputArea_ilql2_48{gap:var(--cascivo-space-2);padding:var(--cascivo-space-3);border-block-start:1px solid var(--cascivo-border-subtle);background:var(--cascivo-color-surface);display:flex}._textarea_ilql2_55{resize:none;border:1px solid var(--cascivo-border-default);border-radius:var(--cascivo-radius-control);padding:var(--cascivo-space-2) var(--cascivo-space-3);font:inherit;background:var(--cascivo-color-background);color:var(--cascivo-color-foreground);flex:1}._sendButton_ilql2_65{padding:var(--cascivo-space-2) var(--cascivo-space-4);background:var(--cascivo-color-accent);color:var(--cascivo-color-accent-foreground);border-radius:var(--cascivo-radius-control);font:inherit;cursor:pointer;border:none;font-weight:500}._sendButton_ilql2_65:disabled{opacity:.5;cursor:not-allowed}}@keyframes _cascade-cursor-blink_1vw7g_1{0%,to{opacity:1}50%{opacity:0}}@keyframes _cascade-ai-pulse_5tg3n_1{0%,to{opacity:1}50%{opacity:.6}}@keyframes _cascade-cursor-blink_1s9z8_1{0%,to{opacity:1}50%{opacity:0}}
|
|
2
|
+
/*$vite$:1*/
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { HTMLAttributes } from "react";
|
|
2
2
|
|
|
3
|
-
//#region src/streaming-text.d.ts
|
|
4
3
|
interface StreamingTextProps {
|
|
5
4
|
text: string;
|
|
6
5
|
speed?: number;
|
|
@@ -13,8 +12,6 @@ declare function StreamingText({
|
|
|
13
12
|
onComplete,
|
|
14
13
|
className
|
|
15
14
|
}: StreamingTextProps): import("react").JSX.Element;
|
|
16
|
-
//#endregion
|
|
17
|
-
//#region src/ai-label.d.ts
|
|
18
15
|
type AiLabelVariant = 'generating' | 'done' | 'error';
|
|
19
16
|
interface AiLabelProps extends HTMLAttributes<HTMLSpanElement> {
|
|
20
17
|
variant?: AiLabelVariant;
|
|
@@ -24,8 +21,6 @@ declare function AiLabel({
|
|
|
24
21
|
className,
|
|
25
22
|
...props
|
|
26
23
|
}: AiLabelProps): import("react").JSX.Element;
|
|
27
|
-
//#endregion
|
|
28
|
-
//#region src/terminal.d.ts
|
|
29
24
|
type TerminalLineType = 'command' | 'output' | 'error' | 'comment';
|
|
30
25
|
interface TerminalLine {
|
|
31
26
|
text: string;
|
|
@@ -46,8 +41,6 @@ declare function Terminal({
|
|
|
46
41
|
onComplete,
|
|
47
42
|
className
|
|
48
43
|
}: TerminalProps): import("react").JSX.Element;
|
|
49
|
-
//#endregion
|
|
50
|
-
//#region src/ai-chat.d.ts
|
|
51
44
|
interface ChatMessage {
|
|
52
45
|
id: string;
|
|
53
46
|
role: 'user' | 'assistant' | 'system';
|
|
@@ -67,6 +60,5 @@ declare function AiChat({
|
|
|
67
60
|
streamingText,
|
|
68
61
|
className
|
|
69
62
|
}: AiChatProps): import("react").JSX.Element;
|
|
70
|
-
//#endregion
|
|
71
63
|
export { AiChat, type AiChatProps, AiLabel, type AiLabelProps, type AiLabelVariant, type ChatMessage, StreamingText, type StreamingTextProps, Terminal, type TerminalLine, type TerminalLineType, type TerminalProps };
|
|
72
64
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import './ai.css';
|
|
3
|
+
import { useRef as e } from "react";
|
|
4
|
+
import { useSignal as t, useSignalEffect as n, useSignals as r } from "@cascivo/core";
|
|
5
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
6
|
+
import { builtin as o, t as s } from "@cascivo/i18n";
|
|
7
|
+
var c = {
|
|
8
|
+
root: "_root_1vw7g_2",
|
|
9
|
+
cursor: "_cursor_1vw7g_5",
|
|
10
|
+
"cascade-cursor-blink": "_cascade-cursor-blink_1vw7g_1"
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/streaming-text.tsx
|
|
14
|
+
function l({ text: o, speed: s = 2, onComplete: l, className: u }) {
|
|
15
|
+
r();
|
|
16
|
+
let d = t(""), f = e(l);
|
|
17
|
+
return f.current = l, d.value = d.value.length > o.length ? "" : d.value, n(() => {
|
|
18
|
+
let e = o;
|
|
19
|
+
if (d.value === e) {
|
|
20
|
+
f.current?.();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
let t;
|
|
24
|
+
function n() {
|
|
25
|
+
let r = d.value;
|
|
26
|
+
if (r.length >= e.length) {
|
|
27
|
+
f.current?.();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
d.value = e.slice(0, r.length + s), t = requestAnimationFrame(n);
|
|
31
|
+
}
|
|
32
|
+
return t = requestAnimationFrame(n), () => cancelAnimationFrame(t);
|
|
33
|
+
}), /* @__PURE__ */ a("span", {
|
|
34
|
+
className: [c.root, u].filter(Boolean).join(" "),
|
|
35
|
+
children: [d.value, d.value !== o && /* @__PURE__ */ i("span", {
|
|
36
|
+
className: c.cursor,
|
|
37
|
+
"aria-hidden": "true"
|
|
38
|
+
})]
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
var u = {
|
|
42
|
+
root: "_root_5tg3n_2",
|
|
43
|
+
"cascade-ai-pulse": "_cascade-ai-pulse_5tg3n_1"
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/ai-label.tsx
|
|
47
|
+
function d({ variant: e = "generating", className: t, ...n }) {
|
|
48
|
+
r();
|
|
49
|
+
let a = s(e === "generating" ? o.ai.generating : e === "done" ? o.ai.done : o.ai.error);
|
|
50
|
+
return /* @__PURE__ */ i("span", {
|
|
51
|
+
role: "status",
|
|
52
|
+
"aria-label": a,
|
|
53
|
+
"data-variant": e,
|
|
54
|
+
className: [u.root, t].filter(Boolean).join(" "),
|
|
55
|
+
...n,
|
|
56
|
+
children: a
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
var f = {
|
|
60
|
+
root: "_root_1s9z8_2",
|
|
61
|
+
line: "_line_1s9z8_12",
|
|
62
|
+
prefix: "_prefix_1s9z8_16",
|
|
63
|
+
text: "_text_1s9z8_20",
|
|
64
|
+
cursor: "_cursor_1s9z8_23",
|
|
65
|
+
"cascade-cursor-blink": "_cascade-cursor-blink_1s9z8_1"
|
|
66
|
+
};
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/terminal.tsx
|
|
69
|
+
function p({ lines: o, speed: s = 3, loop: c = !1, onComplete: l, className: u }) {
|
|
70
|
+
r();
|
|
71
|
+
let d = t(0), p = t(0), m = e(l);
|
|
72
|
+
m.current = l, n(() => {
|
|
73
|
+
if (o.length === 0) return;
|
|
74
|
+
let e;
|
|
75
|
+
function t() {
|
|
76
|
+
let n = d.value, r = p.value;
|
|
77
|
+
if (n >= o.length) {
|
|
78
|
+
m.current?.(), c && (d.value = 0, p.value = 0);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
r < o[n].text.length ? p.value = r + s : (d.value = n + 1, p.value = 0), e = requestAnimationFrame(t);
|
|
82
|
+
}
|
|
83
|
+
return e = requestAnimationFrame(t), () => cancelAnimationFrame(e);
|
|
84
|
+
});
|
|
85
|
+
let h = o.slice(0, d.value + 1).map((e, t) => {
|
|
86
|
+
let n = t === d.value, r = n ? e.text.slice(0, p.value) : e.text;
|
|
87
|
+
return /* @__PURE__ */ a("div", {
|
|
88
|
+
className: f.line,
|
|
89
|
+
"data-type": e.type ?? "output",
|
|
90
|
+
children: [
|
|
91
|
+
e.prefix && /* @__PURE__ */ i("span", {
|
|
92
|
+
className: f.prefix,
|
|
93
|
+
children: e.prefix
|
|
94
|
+
}),
|
|
95
|
+
/* @__PURE__ */ i("span", {
|
|
96
|
+
className: f.text,
|
|
97
|
+
children: r
|
|
98
|
+
}),
|
|
99
|
+
n && d.value < o.length && /* @__PURE__ */ i("span", {
|
|
100
|
+
className: f.cursor,
|
|
101
|
+
"aria-hidden": "true"
|
|
102
|
+
})
|
|
103
|
+
]
|
|
104
|
+
}, t);
|
|
105
|
+
});
|
|
106
|
+
return /* @__PURE__ */ i("div", {
|
|
107
|
+
role: "log",
|
|
108
|
+
"aria-live": "polite",
|
|
109
|
+
"aria-label": "Terminal output",
|
|
110
|
+
className: [f.root, u].filter(Boolean).join(" "),
|
|
111
|
+
children: h
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
var m = {
|
|
115
|
+
root: "_root_ilql2_2",
|
|
116
|
+
messages: "_messages_ilql2_12",
|
|
117
|
+
message: "_message_ilql2_12",
|
|
118
|
+
roleLabel: "_roleLabel_ilql2_33",
|
|
119
|
+
content: "_content_ilql2_38",
|
|
120
|
+
inputArea: "_inputArea_ilql2_48",
|
|
121
|
+
textarea: "_textarea_ilql2_55",
|
|
122
|
+
sendButton: "_sendButton_ilql2_65"
|
|
123
|
+
};
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/ai-chat.tsx
|
|
126
|
+
function h({ messages: n, onSend: c, isStreaming: u = !1, streamingText: d, className: f }) {
|
|
127
|
+
r();
|
|
128
|
+
let p = t(""), h = e(null);
|
|
129
|
+
function g() {
|
|
130
|
+
let e = p.value.trim();
|
|
131
|
+
e && (c(e), p.value = "");
|
|
132
|
+
}
|
|
133
|
+
function _(e) {
|
|
134
|
+
e.key === "Enter" && !e.shiftKey && (e.preventDefault(), g());
|
|
135
|
+
}
|
|
136
|
+
return /* @__PURE__ */ a("div", {
|
|
137
|
+
className: [m.root, f].filter(Boolean).join(" "),
|
|
138
|
+
children: [/* @__PURE__ */ a("div", {
|
|
139
|
+
ref: h,
|
|
140
|
+
className: m.messages,
|
|
141
|
+
role: "log",
|
|
142
|
+
"aria-live": "polite",
|
|
143
|
+
children: [n.filter((e) => e.role !== "system").map((e) => /* @__PURE__ */ a("div", {
|
|
144
|
+
className: m.message,
|
|
145
|
+
"data-role": e.role,
|
|
146
|
+
children: [/* @__PURE__ */ i("span", {
|
|
147
|
+
className: m.roleLabel,
|
|
148
|
+
children: e.role === "user" ? s(o.ai.you) : s(o.ai.assistant)
|
|
149
|
+
}), /* @__PURE__ */ i("div", {
|
|
150
|
+
className: m.content,
|
|
151
|
+
children: e.content
|
|
152
|
+
})]
|
|
153
|
+
}, e.id)), u && d !== void 0 && /* @__PURE__ */ a("div", {
|
|
154
|
+
className: m.message,
|
|
155
|
+
"data-role": "assistant",
|
|
156
|
+
children: [/* @__PURE__ */ i("span", {
|
|
157
|
+
className: m.roleLabel,
|
|
158
|
+
children: s(o.ai.assistant)
|
|
159
|
+
}), /* @__PURE__ */ i("div", {
|
|
160
|
+
className: m.content,
|
|
161
|
+
children: /* @__PURE__ */ i(l, { text: d })
|
|
162
|
+
})]
|
|
163
|
+
})]
|
|
164
|
+
}), /* @__PURE__ */ a("div", {
|
|
165
|
+
className: m.inputArea,
|
|
166
|
+
children: [/* @__PURE__ */ i("textarea", {
|
|
167
|
+
className: m.textarea,
|
|
168
|
+
placeholder: s(o.ai.placeholder),
|
|
169
|
+
value: p.value,
|
|
170
|
+
onChange: (e) => {
|
|
171
|
+
p.value = e.target.value;
|
|
172
|
+
},
|
|
173
|
+
onKeyDown: _,
|
|
174
|
+
rows: 1,
|
|
175
|
+
"aria-label": s(o.ai.placeholder)
|
|
176
|
+
}), /* @__PURE__ */ i("button", {
|
|
177
|
+
type: "button",
|
|
178
|
+
className: m.sendButton,
|
|
179
|
+
onClick: g,
|
|
180
|
+
disabled: u,
|
|
181
|
+
"aria-label": s(o.ai.send),
|
|
182
|
+
children: s(o.ai.send)
|
|
183
|
+
})]
|
|
184
|
+
})]
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
//#endregion
|
|
188
|
+
export { h as AiChat, d as AiLabel, l as StreamingText, p as Terminal };
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRef as e } from "react";
|
|
3
|
+
import { useSignal as t, useSignalEffect as n, useSignals as r } from "@cascivo/core";
|
|
4
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
|
+
import { builtin as o, t as s } from "@cascivo/i18n";
|
|
6
|
+
var c = {
|
|
7
|
+
root: "_root_1vw7g_2",
|
|
8
|
+
cursor: "_cursor_1vw7g_5",
|
|
9
|
+
"cascade-cursor-blink": "_cascade-cursor-blink_1vw7g_1"
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/streaming-text.tsx
|
|
13
|
+
function l({ text: o, speed: s = 2, onComplete: l, className: u }) {
|
|
14
|
+
r();
|
|
15
|
+
let d = t(""), f = e(l);
|
|
16
|
+
return f.current = l, d.value = d.value.length > o.length ? "" : d.value, n(() => {
|
|
17
|
+
let e = o;
|
|
18
|
+
if (d.value === e) {
|
|
19
|
+
f.current?.();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
let t;
|
|
23
|
+
function n() {
|
|
24
|
+
let r = d.value;
|
|
25
|
+
if (r.length >= e.length) {
|
|
26
|
+
f.current?.();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
d.value = e.slice(0, r.length + s), t = requestAnimationFrame(n);
|
|
30
|
+
}
|
|
31
|
+
return t = requestAnimationFrame(n), () => cancelAnimationFrame(t);
|
|
32
|
+
}), /* @__PURE__ */ a("span", {
|
|
33
|
+
className: [c.root, u].filter(Boolean).join(" "),
|
|
34
|
+
children: [d.value, d.value !== o && /* @__PURE__ */ i("span", {
|
|
35
|
+
className: c.cursor,
|
|
36
|
+
"aria-hidden": "true"
|
|
37
|
+
})]
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
var u = {
|
|
41
|
+
root: "_root_5tg3n_2",
|
|
42
|
+
"cascade-ai-pulse": "_cascade-ai-pulse_5tg3n_1"
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/ai-label.tsx
|
|
46
|
+
function d({ variant: e = "generating", className: t, ...n }) {
|
|
47
|
+
r();
|
|
48
|
+
let a = s(e === "generating" ? o.ai.generating : e === "done" ? o.ai.done : o.ai.error);
|
|
49
|
+
return /* @__PURE__ */ i("span", {
|
|
50
|
+
role: "status",
|
|
51
|
+
"aria-label": a,
|
|
52
|
+
"data-variant": e,
|
|
53
|
+
className: [u.root, t].filter(Boolean).join(" "),
|
|
54
|
+
...n,
|
|
55
|
+
children: a
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
var f = {
|
|
59
|
+
root: "_root_1s9z8_2",
|
|
60
|
+
line: "_line_1s9z8_12",
|
|
61
|
+
prefix: "_prefix_1s9z8_16",
|
|
62
|
+
text: "_text_1s9z8_20",
|
|
63
|
+
cursor: "_cursor_1s9z8_23",
|
|
64
|
+
"cascade-cursor-blink": "_cascade-cursor-blink_1s9z8_1"
|
|
65
|
+
};
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/terminal.tsx
|
|
68
|
+
function p({ lines: o, speed: s = 3, loop: c = !1, onComplete: l, className: u }) {
|
|
69
|
+
r();
|
|
70
|
+
let d = t(0), p = t(0), m = e(l);
|
|
71
|
+
m.current = l, n(() => {
|
|
72
|
+
if (o.length === 0) return;
|
|
73
|
+
let e;
|
|
74
|
+
function t() {
|
|
75
|
+
let n = d.value, r = p.value;
|
|
76
|
+
if (n >= o.length) {
|
|
77
|
+
m.current?.(), c && (d.value = 0, p.value = 0);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
r < o[n].text.length ? p.value = r + s : (d.value = n + 1, p.value = 0), e = requestAnimationFrame(t);
|
|
81
|
+
}
|
|
82
|
+
return e = requestAnimationFrame(t), () => cancelAnimationFrame(e);
|
|
83
|
+
});
|
|
84
|
+
let h = o.slice(0, d.value + 1).map((e, t) => {
|
|
85
|
+
let n = t === d.value, r = n ? e.text.slice(0, p.value) : e.text;
|
|
86
|
+
return /* @__PURE__ */ a("div", {
|
|
87
|
+
className: f.line,
|
|
88
|
+
"data-type": e.type ?? "output",
|
|
89
|
+
children: [
|
|
90
|
+
e.prefix && /* @__PURE__ */ i("span", {
|
|
91
|
+
className: f.prefix,
|
|
92
|
+
children: e.prefix
|
|
93
|
+
}),
|
|
94
|
+
/* @__PURE__ */ i("span", {
|
|
95
|
+
className: f.text,
|
|
96
|
+
children: r
|
|
97
|
+
}),
|
|
98
|
+
n && d.value < o.length && /* @__PURE__ */ i("span", {
|
|
99
|
+
className: f.cursor,
|
|
100
|
+
"aria-hidden": "true"
|
|
101
|
+
})
|
|
102
|
+
]
|
|
103
|
+
}, t);
|
|
104
|
+
});
|
|
105
|
+
return /* @__PURE__ */ i("div", {
|
|
106
|
+
role: "log",
|
|
107
|
+
"aria-live": "polite",
|
|
108
|
+
"aria-label": "Terminal output",
|
|
109
|
+
className: [f.root, u].filter(Boolean).join(" "),
|
|
110
|
+
children: h
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
var m = {
|
|
114
|
+
root: "_root_ilql2_2",
|
|
115
|
+
messages: "_messages_ilql2_12",
|
|
116
|
+
message: "_message_ilql2_12",
|
|
117
|
+
roleLabel: "_roleLabel_ilql2_33",
|
|
118
|
+
content: "_content_ilql2_38",
|
|
119
|
+
inputArea: "_inputArea_ilql2_48",
|
|
120
|
+
textarea: "_textarea_ilql2_55",
|
|
121
|
+
sendButton: "_sendButton_ilql2_65"
|
|
122
|
+
};
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/ai-chat.tsx
|
|
125
|
+
function h({ messages: n, onSend: c, isStreaming: u = !1, streamingText: d, className: f }) {
|
|
126
|
+
r();
|
|
127
|
+
let p = t(""), h = e(null);
|
|
128
|
+
function g() {
|
|
129
|
+
let e = p.value.trim();
|
|
130
|
+
e && (c(e), p.value = "");
|
|
131
|
+
}
|
|
132
|
+
function _(e) {
|
|
133
|
+
e.key === "Enter" && !e.shiftKey && (e.preventDefault(), g());
|
|
134
|
+
}
|
|
135
|
+
return /* @__PURE__ */ a("div", {
|
|
136
|
+
className: [m.root, f].filter(Boolean).join(" "),
|
|
137
|
+
children: [/* @__PURE__ */ a("div", {
|
|
138
|
+
ref: h,
|
|
139
|
+
className: m.messages,
|
|
140
|
+
role: "log",
|
|
141
|
+
"aria-live": "polite",
|
|
142
|
+
children: [n.filter((e) => e.role !== "system").map((e) => /* @__PURE__ */ a("div", {
|
|
143
|
+
className: m.message,
|
|
144
|
+
"data-role": e.role,
|
|
145
|
+
children: [/* @__PURE__ */ i("span", {
|
|
146
|
+
className: m.roleLabel,
|
|
147
|
+
children: e.role === "user" ? s(o.ai.you) : s(o.ai.assistant)
|
|
148
|
+
}), /* @__PURE__ */ i("div", {
|
|
149
|
+
className: m.content,
|
|
150
|
+
children: e.content
|
|
151
|
+
})]
|
|
152
|
+
}, e.id)), u && d !== void 0 && /* @__PURE__ */ a("div", {
|
|
153
|
+
className: m.message,
|
|
154
|
+
"data-role": "assistant",
|
|
155
|
+
children: [/* @__PURE__ */ i("span", {
|
|
156
|
+
className: m.roleLabel,
|
|
157
|
+
children: s(o.ai.assistant)
|
|
158
|
+
}), /* @__PURE__ */ i("div", {
|
|
159
|
+
className: m.content,
|
|
160
|
+
children: /* @__PURE__ */ i(l, { text: d })
|
|
161
|
+
})]
|
|
162
|
+
})]
|
|
163
|
+
}), /* @__PURE__ */ a("div", {
|
|
164
|
+
className: m.inputArea,
|
|
165
|
+
children: [/* @__PURE__ */ i("textarea", {
|
|
166
|
+
className: m.textarea,
|
|
167
|
+
placeholder: s(o.ai.placeholder),
|
|
168
|
+
value: p.value,
|
|
169
|
+
onChange: (e) => {
|
|
170
|
+
p.value = e.target.value;
|
|
171
|
+
},
|
|
172
|
+
onKeyDown: _,
|
|
173
|
+
rows: 1,
|
|
174
|
+
"aria-label": s(o.ai.placeholder)
|
|
175
|
+
}), /* @__PURE__ */ i("button", {
|
|
176
|
+
type: "button",
|
|
177
|
+
className: m.sendButton,
|
|
178
|
+
onClick: g,
|
|
179
|
+
disabled: u,
|
|
180
|
+
"aria-label": s(o.ai.send),
|
|
181
|
+
children: s(o.ai.send)
|
|
182
|
+
})]
|
|
183
|
+
})]
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
187
|
+
export { h as AiChat, d as AiLabel, l as StreamingText, p as Terminal };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cascivo/ai",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"description": "AI-native components for cascivo — StreamingText, AiLabel, Terminal, AiChat",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -27,13 +27,14 @@
|
|
|
27
27
|
"sideEffects": [
|
|
28
28
|
"**/*.css"
|
|
29
29
|
],
|
|
30
|
-
"types": "./dist/index.d.
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
31
|
"exports": {
|
|
32
32
|
"./package.json": "./package.json",
|
|
33
33
|
".": {
|
|
34
|
-
"types": "./dist/index.d.
|
|
35
|
-
"
|
|
36
|
-
"
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"node": "./dist/node/index.js",
|
|
36
|
+
"import": "./dist/index.js",
|
|
37
|
+
"default": "./dist/index.js"
|
|
37
38
|
}
|
|
38
39
|
},
|
|
39
40
|
"publishConfig": {
|
|
@@ -41,9 +42,9 @@
|
|
|
41
42
|
"provenance": true
|
|
42
43
|
},
|
|
43
44
|
"dependencies": {
|
|
44
|
-
"@cascivo/core": "^0.
|
|
45
|
-
"@cascivo/i18n": "^0.2.
|
|
46
|
-
"@cascivo/tokens": "^0.5.
|
|
45
|
+
"@cascivo/core": "^0.7.1",
|
|
46
|
+
"@cascivo/i18n": "^0.2.14",
|
|
47
|
+
"@cascivo/tokens": "^0.5.6"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
49
50
|
"@testing-library/jest-dom": "^6.9.1",
|
|
@@ -56,10 +57,16 @@
|
|
|
56
57
|
},
|
|
57
58
|
"peerDependencies": {
|
|
58
59
|
"@preact/signals-react": ">=3.0.0",
|
|
60
|
+
"@types/react": ">=18.0.0",
|
|
59
61
|
"react": ">=18.0.0"
|
|
60
62
|
},
|
|
63
|
+
"peerDependenciesMeta": {
|
|
64
|
+
"@types/react": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
61
68
|
"scripts": {
|
|
62
|
-
"build": "vp
|
|
69
|
+
"build": "vp build && node scripts/flatten-types.mjs && node scripts/check-types-flat.mjs",
|
|
63
70
|
"check": "tsc --noEmit",
|
|
64
71
|
"test": "vp test",
|
|
65
72
|
"dev": "vp pack --watch"
|
package/dist/index.d.mts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/streaming-text.tsx","../src/ai-label.tsx","../src/terminal.tsx","../src/ai-chat.tsx"],"mappings":";;;UAKiB,kBAAA;EACf,IAAA;EACA,KAAA;EACA,UAAA;EACA,SAAA;AAAA;AAAA,iBAGc,aAAA;EAAgB,IAAA;EAAM,KAAA;EAAW,UAAA;EAAY;AAAA,GAAa,kBAAA,mBAAkB,GAAA,CAAA,OAAA;;;KCNhF,cAAA;AAAA,UAEK,YAAA,SAAqB,cAAA,CAAe,eAAA;EACnD,OAAA,GAAU,cAAA;AAAA;AAAA,iBAGI,OAAA;EAAU,OAAA;EAAwB,SAAA;EAAA,GAAc;AAAA,GAAS,YAAA,mBAAY,GAAA,CAAA,OAAA;;;KCPzE,gBAAA;AAAA,UAEK,YAAA;EACf,IAAA;EACA,MAAA;EACA,IAAA,GAAO,gBAAgB;AAAA;AAAA,UAGR,aAAA;EACf,KAAA,EAAO,YAAY;EACnB,KAAA;EACA,IAAA;EACA,UAAA;EACA,SAAA;AAAA;AAAA,iBAGc,QAAA;EAAW,KAAA;EAAO,KAAA;EAAW,IAAA;EAAc,UAAA;EAAY;AAAA,GAAa,aAAA,mBAAa,GAAA,CAAA,OAAA;;;UCdhF,WAAA;EACf,EAAA;EACA,IAAA;EACA,OAAA;AAAA;AAAA,UAGe,WAAA;EACf,QAAA,EAAU,WAAW;EACrB,MAAA,GAAS,IAAA;EACT,WAAA;EACA,aAAA;EACA,SAAA;AAAA;AAAA,iBAGc,MAAA;EACd,QAAA;EACA,MAAA;EACA,WAAA;EACA,aAAA;EACA;AAAA,GACC,WAAA,mBAAW,GAAA,CAAA,OAAA"}
|
package/dist/index.mjs
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
import { useRef } from "react";
|
|
2
|
-
import { useSignal, useSignalEffect, useSignals } from "@cascivo/core";
|
|
3
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
-
import { builtin, t } from "@cascivo/i18n";
|
|
5
|
-
//#region src/streaming-text.module.css
|
|
6
|
-
var streaming_text_module_default = {
|
|
7
|
-
"cascade-cursor-blink": "RTCb2G_cascade-cursor-blink",
|
|
8
|
-
"cursor": "RTCb2G_cursor",
|
|
9
|
-
"root": "RTCb2G_root"
|
|
10
|
-
};
|
|
11
|
-
//#endregion
|
|
12
|
-
//#region src/streaming-text.tsx
|
|
13
|
-
function StreamingText({ text, speed = 2, onComplete, className }) {
|
|
14
|
-
useSignals();
|
|
15
|
-
const displayed = useSignal("");
|
|
16
|
-
const onCompleteRef = useRef(onComplete);
|
|
17
|
-
onCompleteRef.current = onComplete;
|
|
18
|
-
displayed.value = displayed.value.length > text.length ? "" : displayed.value;
|
|
19
|
-
useSignalEffect(() => {
|
|
20
|
-
const target = text;
|
|
21
|
-
if (displayed.value === target) {
|
|
22
|
-
onCompleteRef.current?.();
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
let rafId;
|
|
26
|
-
function tick() {
|
|
27
|
-
const current = displayed.value;
|
|
28
|
-
if (current.length >= target.length) {
|
|
29
|
-
onCompleteRef.current?.();
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
displayed.value = target.slice(0, current.length + speed);
|
|
33
|
-
rafId = requestAnimationFrame(tick);
|
|
34
|
-
}
|
|
35
|
-
rafId = requestAnimationFrame(tick);
|
|
36
|
-
return () => cancelAnimationFrame(rafId);
|
|
37
|
-
});
|
|
38
|
-
return /* @__PURE__ */ jsxs("span", {
|
|
39
|
-
className: [streaming_text_module_default.root, className].filter(Boolean).join(" "),
|
|
40
|
-
children: [displayed.value, displayed.value !== text && /* @__PURE__ */ jsx("span", {
|
|
41
|
-
className: streaming_text_module_default.cursor,
|
|
42
|
-
"aria-hidden": "true"
|
|
43
|
-
})]
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
//#endregion
|
|
47
|
-
//#region src/ai-label.module.css
|
|
48
|
-
var ai_label_module_default = {
|
|
49
|
-
"cascade-ai-pulse": "_zzYFW_cascade-ai-pulse",
|
|
50
|
-
"root": "_zzYFW_root"
|
|
51
|
-
};
|
|
52
|
-
//#endregion
|
|
53
|
-
//#region src/ai-label.tsx
|
|
54
|
-
function AiLabel({ variant = "generating", className, ...props }) {
|
|
55
|
-
useSignals();
|
|
56
|
-
const label = variant === "generating" ? t(builtin.ai.generating) : variant === "done" ? t(builtin.ai.done) : t(builtin.ai.error);
|
|
57
|
-
return /* @__PURE__ */ jsx("span", {
|
|
58
|
-
role: "status",
|
|
59
|
-
"aria-label": label,
|
|
60
|
-
"data-variant": variant,
|
|
61
|
-
className: [ai_label_module_default.root, className].filter(Boolean).join(" "),
|
|
62
|
-
...props,
|
|
63
|
-
children: label
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
//#endregion
|
|
67
|
-
//#region src/terminal.module.css
|
|
68
|
-
var terminal_module_default = {
|
|
69
|
-
"cascade-cursor-blink": "sxMVlG_cascade-cursor-blink",
|
|
70
|
-
"cursor": "sxMVlG_cursor",
|
|
71
|
-
"line": "sxMVlG_line",
|
|
72
|
-
"prefix": "sxMVlG_prefix",
|
|
73
|
-
"root": "sxMVlG_root",
|
|
74
|
-
"text": "sxMVlG_text"
|
|
75
|
-
};
|
|
76
|
-
//#endregion
|
|
77
|
-
//#region src/terminal.tsx
|
|
78
|
-
function Terminal({ lines, speed = 3, loop = false, onComplete, className }) {
|
|
79
|
-
useSignals();
|
|
80
|
-
const lineIndex = useSignal(0);
|
|
81
|
-
const charIndex = useSignal(0);
|
|
82
|
-
const onCompleteRef = useRef(onComplete);
|
|
83
|
-
onCompleteRef.current = onComplete;
|
|
84
|
-
useSignalEffect(() => {
|
|
85
|
-
if (lines.length === 0) return;
|
|
86
|
-
let rafId;
|
|
87
|
-
function tick() {
|
|
88
|
-
const li = lineIndex.value;
|
|
89
|
-
const ci = charIndex.value;
|
|
90
|
-
if (li >= lines.length) {
|
|
91
|
-
onCompleteRef.current?.();
|
|
92
|
-
if (loop) {
|
|
93
|
-
lineIndex.value = 0;
|
|
94
|
-
charIndex.value = 0;
|
|
95
|
-
}
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
if (ci < lines[li].text.length) charIndex.value = ci + speed;
|
|
99
|
-
else {
|
|
100
|
-
lineIndex.value = li + 1;
|
|
101
|
-
charIndex.value = 0;
|
|
102
|
-
}
|
|
103
|
-
rafId = requestAnimationFrame(tick);
|
|
104
|
-
}
|
|
105
|
-
rafId = requestAnimationFrame(tick);
|
|
106
|
-
return () => cancelAnimationFrame(rafId);
|
|
107
|
-
});
|
|
108
|
-
const renderedLines = lines.slice(0, lineIndex.value + 1).map((line, i) => {
|
|
109
|
-
const isCurrentLine = i === lineIndex.value;
|
|
110
|
-
const text = isCurrentLine ? line.text.slice(0, charIndex.value) : line.text;
|
|
111
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
112
|
-
className: terminal_module_default.line,
|
|
113
|
-
"data-type": line.type ?? "output",
|
|
114
|
-
children: [
|
|
115
|
-
line.prefix && /* @__PURE__ */ jsx("span", {
|
|
116
|
-
className: terminal_module_default.prefix,
|
|
117
|
-
children: line.prefix
|
|
118
|
-
}),
|
|
119
|
-
/* @__PURE__ */ jsx("span", {
|
|
120
|
-
className: terminal_module_default.text,
|
|
121
|
-
children: text
|
|
122
|
-
}),
|
|
123
|
-
isCurrentLine && lineIndex.value < lines.length && /* @__PURE__ */ jsx("span", {
|
|
124
|
-
className: terminal_module_default.cursor,
|
|
125
|
-
"aria-hidden": "true"
|
|
126
|
-
})
|
|
127
|
-
]
|
|
128
|
-
}, i);
|
|
129
|
-
});
|
|
130
|
-
return /* @__PURE__ */ jsx("div", {
|
|
131
|
-
role: "log",
|
|
132
|
-
"aria-live": "polite",
|
|
133
|
-
"aria-label": "Terminal output",
|
|
134
|
-
className: [terminal_module_default.root, className].filter(Boolean).join(" "),
|
|
135
|
-
children: renderedLines
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
//#endregion
|
|
139
|
-
//#region src/ai-chat.module.css
|
|
140
|
-
var ai_chat_module_default = {
|
|
141
|
-
"content": "GEItsa_content",
|
|
142
|
-
"inputArea": "GEItsa_inputArea",
|
|
143
|
-
"message": "GEItsa_message",
|
|
144
|
-
"messages": "GEItsa_messages",
|
|
145
|
-
"roleLabel": "GEItsa_roleLabel",
|
|
146
|
-
"root": "GEItsa_root",
|
|
147
|
-
"sendButton": "GEItsa_sendButton",
|
|
148
|
-
"textarea": "GEItsa_textarea"
|
|
149
|
-
};
|
|
150
|
-
//#endregion
|
|
151
|
-
//#region src/ai-chat.tsx
|
|
152
|
-
function AiChat({ messages, onSend, isStreaming = false, streamingText, className }) {
|
|
153
|
-
useSignals();
|
|
154
|
-
const inputValue = useSignal("");
|
|
155
|
-
const listRef = useRef(null);
|
|
156
|
-
function handleSend() {
|
|
157
|
-
const text = inputValue.value.trim();
|
|
158
|
-
if (!text) return;
|
|
159
|
-
onSend(text);
|
|
160
|
-
inputValue.value = "";
|
|
161
|
-
}
|
|
162
|
-
function handleKeyDown(e) {
|
|
163
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
164
|
-
e.preventDefault();
|
|
165
|
-
handleSend();
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
169
|
-
className: [ai_chat_module_default.root, className].filter(Boolean).join(" "),
|
|
170
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
171
|
-
ref: listRef,
|
|
172
|
-
className: ai_chat_module_default.messages,
|
|
173
|
-
role: "log",
|
|
174
|
-
"aria-live": "polite",
|
|
175
|
-
children: [messages.filter((m) => m.role !== "system").map((msg) => /* @__PURE__ */ jsxs("div", {
|
|
176
|
-
className: ai_chat_module_default.message,
|
|
177
|
-
"data-role": msg.role,
|
|
178
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
179
|
-
className: ai_chat_module_default.roleLabel,
|
|
180
|
-
children: msg.role === "user" ? t(builtin.ai.you) : t(builtin.ai.assistant)
|
|
181
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
182
|
-
className: ai_chat_module_default.content,
|
|
183
|
-
children: msg.content
|
|
184
|
-
})]
|
|
185
|
-
}, msg.id)), isStreaming && streamingText !== void 0 && /* @__PURE__ */ jsxs("div", {
|
|
186
|
-
className: ai_chat_module_default.message,
|
|
187
|
-
"data-role": "assistant",
|
|
188
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
189
|
-
className: ai_chat_module_default.roleLabel,
|
|
190
|
-
children: t(builtin.ai.assistant)
|
|
191
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
192
|
-
className: ai_chat_module_default.content,
|
|
193
|
-
children: /* @__PURE__ */ jsx(StreamingText, { text: streamingText })
|
|
194
|
-
})]
|
|
195
|
-
})]
|
|
196
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
197
|
-
className: ai_chat_module_default.inputArea,
|
|
198
|
-
children: [/* @__PURE__ */ jsx("textarea", {
|
|
199
|
-
className: ai_chat_module_default.textarea,
|
|
200
|
-
placeholder: t(builtin.ai.placeholder),
|
|
201
|
-
value: inputValue.value,
|
|
202
|
-
onChange: (e) => {
|
|
203
|
-
inputValue.value = e.target.value;
|
|
204
|
-
},
|
|
205
|
-
onKeyDown: handleKeyDown,
|
|
206
|
-
rows: 1,
|
|
207
|
-
"aria-label": t(builtin.ai.placeholder)
|
|
208
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
209
|
-
type: "button",
|
|
210
|
-
className: ai_chat_module_default.sendButton,
|
|
211
|
-
onClick: handleSend,
|
|
212
|
-
disabled: isStreaming,
|
|
213
|
-
"aria-label": t(builtin.ai.send),
|
|
214
|
-
children: t(builtin.ai.send)
|
|
215
|
-
})]
|
|
216
|
-
})]
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
//#endregion
|
|
220
|
-
export { AiChat, AiLabel, StreamingText, Terminal };
|
|
221
|
-
|
|
222
|
-
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["styles","styles","styles","styles"],"sources":["../src/streaming-text.tsx","../src/ai-label.tsx","../src/terminal.tsx","../src/ai-chat.tsx"],"sourcesContent":["'use client'\nimport { useRef } from 'react'\nimport { useSignal, useSignalEffect, useSignals } from '@cascivo/core'\nimport styles from './streaming-text.module.css'\n\nexport interface StreamingTextProps {\n text: string\n speed?: number\n onComplete?: () => void\n className?: string\n}\n\nexport function StreamingText({ text, speed = 2, onComplete, className }: StreamingTextProps) {\n useSignals()\n const displayed = useSignal('')\n const onCompleteRef = useRef(onComplete)\n onCompleteRef.current = onComplete\n\n // Reset when text prop changes\n displayed.value = displayed.value.length > text.length ? '' : displayed.value\n\n useSignalEffect(() => {\n const target = text\n if (displayed.value === target) {\n onCompleteRef.current?.()\n return\n }\n let rafId: number\n function tick() {\n const current = displayed.value\n if (current.length >= target.length) {\n onCompleteRef.current?.()\n return\n }\n displayed.value = target.slice(0, current.length + speed)\n rafId = requestAnimationFrame(tick)\n }\n rafId = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(rafId)\n })\n\n return (\n <span className={[styles.root, className].filter(Boolean).join(' ')}>\n {displayed.value}\n {displayed.value !== text && <span className={styles.cursor} aria-hidden=\"true\" />}\n </span>\n )\n}\n","'use client'\nimport { useSignals } from '@cascivo/core'\nimport { builtin, t } from '@cascivo/i18n'\nimport styles from './ai-label.module.css'\nimport type { HTMLAttributes } from 'react'\n\nexport type AiLabelVariant = 'generating' | 'done' | 'error'\n\nexport interface AiLabelProps extends HTMLAttributes<HTMLSpanElement> {\n variant?: AiLabelVariant\n}\n\nexport function AiLabel({ variant = 'generating', className, ...props }: AiLabelProps) {\n useSignals()\n const label =\n variant === 'generating'\n ? t(builtin.ai.generating)\n : variant === 'done'\n ? t(builtin.ai.done)\n : t(builtin.ai.error)\n\n return (\n <span\n role=\"status\"\n aria-label={label}\n data-variant={variant}\n className={[styles.root, className].filter(Boolean).join(' ')}\n {...props}\n >\n {label}\n </span>\n )\n}\n","'use client'\nimport { useRef } from 'react'\nimport { useSignal, useSignalEffect, useSignals } from '@cascivo/core'\nimport styles from './terminal.module.css'\n\nexport type TerminalLineType = 'command' | 'output' | 'error' | 'comment'\n\nexport interface TerminalLine {\n text: string\n prefix?: string\n type?: TerminalLineType\n}\n\nexport interface TerminalProps {\n lines: TerminalLine[]\n speed?: number\n loop?: boolean\n onComplete?: () => void\n className?: string\n}\n\nexport function Terminal({ lines, speed = 3, loop = false, onComplete, className }: TerminalProps) {\n useSignals()\n const lineIndex = useSignal(0)\n const charIndex = useSignal(0)\n const onCompleteRef = useRef(onComplete)\n onCompleteRef.current = onComplete\n\n useSignalEffect(() => {\n if (lines.length === 0) return\n let rafId: number\n function tick() {\n const li = lineIndex.value\n const ci = charIndex.value\n if (li >= lines.length) {\n onCompleteRef.current?.()\n if (loop) {\n lineIndex.value = 0\n charIndex.value = 0\n }\n return\n }\n const line = lines[li]!\n const target = line.text\n if (ci < target.length) {\n charIndex.value = ci + speed\n } else {\n lineIndex.value = li + 1\n charIndex.value = 0\n }\n rafId = requestAnimationFrame(tick)\n }\n rafId = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(rafId)\n })\n\n const renderedLines = lines.slice(0, lineIndex.value + 1).map((line, i) => {\n const isCurrentLine = i === lineIndex.value\n const text = isCurrentLine ? line.text.slice(0, charIndex.value) : line.text\n return (\n <div key={i} className={styles.line} data-type={line.type ?? 'output'}>\n {line.prefix && <span className={styles.prefix}>{line.prefix}</span>}\n <span className={styles.text}>{text}</span>\n {isCurrentLine && lineIndex.value < lines.length && (\n <span className={styles.cursor} aria-hidden=\"true\" />\n )}\n </div>\n )\n })\n\n return (\n <div\n role=\"log\"\n aria-live=\"polite\"\n aria-label=\"Terminal output\"\n className={[styles.root, className].filter(Boolean).join(' ')}\n >\n {renderedLines}\n </div>\n )\n}\n","'use client'\nimport { useRef } from 'react'\nimport { useSignal, useSignals } from '@cascivo/core'\nimport { builtin, t } from '@cascivo/i18n'\nimport { StreamingText } from './streaming-text'\nimport styles from './ai-chat.module.css'\n\nexport interface ChatMessage {\n id: string\n role: 'user' | 'assistant' | 'system'\n content: string\n}\n\nexport interface AiChatProps {\n messages: ChatMessage[]\n onSend: (text: string) => void\n isStreaming?: boolean\n streamingText?: string\n className?: string\n}\n\nexport function AiChat({\n messages,\n onSend,\n isStreaming = false,\n streamingText,\n className,\n}: AiChatProps) {\n useSignals()\n const inputValue = useSignal('')\n const listRef = useRef<HTMLDivElement>(null)\n\n function handleSend() {\n const text = inputValue.value.trim()\n if (!text) return\n onSend(text)\n inputValue.value = ''\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLTextAreaElement>) {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n handleSend()\n }\n }\n\n return (\n <div className={[styles.root, className].filter(Boolean).join(' ')}>\n <div ref={listRef} className={styles.messages} role=\"log\" aria-live=\"polite\">\n {messages\n .filter((m) => m.role !== 'system')\n .map((msg) => (\n <div key={msg.id} className={styles.message} data-role={msg.role}>\n <span className={styles.roleLabel}>\n {msg.role === 'user' ? t(builtin.ai.you) : t(builtin.ai.assistant)}\n </span>\n <div className={styles.content}>{msg.content}</div>\n </div>\n ))}\n {isStreaming && streamingText !== undefined && (\n <div className={styles.message} data-role=\"assistant\">\n <span className={styles.roleLabel}>{t(builtin.ai.assistant)}</span>\n <div className={styles.content}>\n <StreamingText text={streamingText} />\n </div>\n </div>\n )}\n </div>\n <div className={styles.inputArea}>\n <textarea\n className={styles.textarea}\n placeholder={t(builtin.ai.placeholder)}\n value={inputValue.value}\n onChange={(e) => {\n inputValue.value = e.target.value\n }}\n onKeyDown={handleKeyDown}\n rows={1}\n aria-label={t(builtin.ai.placeholder)}\n />\n <button\n type=\"button\"\n className={styles.sendButton}\n onClick={handleSend}\n disabled={isStreaming}\n aria-label={t(builtin.ai.send)}\n >\n {t(builtin.ai.send)}\n </button>\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
|
package/dist/style.css
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
@layer cascivo.component {
|
|
2
|
-
.RTCb2G_root {
|
|
3
|
-
display: inline;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
.RTCb2G_cursor {
|
|
7
|
-
vertical-align: text-bottom;
|
|
8
|
-
background: currentColor;
|
|
9
|
-
width: 2px;
|
|
10
|
-
height: 1em;
|
|
11
|
-
margin-inline-start: 1px;
|
|
12
|
-
animation: 1s step-end infinite RTCb2G_cascade-cursor-blink;
|
|
13
|
-
display: inline-block;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
@keyframes RTCb2G_cascade-cursor-blink {
|
|
18
|
-
0%, 100% {
|
|
19
|
-
opacity: 1;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
50% {
|
|
23
|
-
opacity: 0;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
@layer cascivo.component {
|
|
27
|
-
._zzYFW_root {
|
|
28
|
-
align-items: center;
|
|
29
|
-
gap: var(--cascivo-space-1);
|
|
30
|
-
padding: var(--cascivo-space-1) var(--cascivo-space-2);
|
|
31
|
-
border-radius: var(--cascivo-radius-indicator);
|
|
32
|
-
font-size: var(--cascivo-font-size-xs);
|
|
33
|
-
font-weight: 500;
|
|
34
|
-
line-height: 1;
|
|
35
|
-
display: inline-flex;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
._zzYFW_root[data-variant="generating"] {
|
|
39
|
-
background: var(--cascivo-color-surface-2);
|
|
40
|
-
color: var(--cascivo-color-foreground-muted);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
._zzYFW_root[data-variant="generating"]:before {
|
|
44
|
-
content: "";
|
|
45
|
-
border-radius: var(--cascivo-radius-full);
|
|
46
|
-
background: currentColor;
|
|
47
|
-
block-size: .375rem;
|
|
48
|
-
inline-size: .375rem;
|
|
49
|
-
animation: 1.5s ease-in-out infinite _zzYFW_cascade-ai-pulse;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
._zzYFW_root[data-variant="done"] {
|
|
53
|
-
background: var(--cascivo-color-success-subtle);
|
|
54
|
-
color: var(--cascivo-color-success-foreground);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
._zzYFW_root[data-variant="error"] {
|
|
58
|
-
background: var(--cascivo-color-destructive-subtle);
|
|
59
|
-
color: var(--cascivo-color-destructive-foreground);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
@keyframes _zzYFW_cascade-ai-pulse {
|
|
64
|
-
0%, 100% {
|
|
65
|
-
opacity: 1;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
50% {
|
|
69
|
-
opacity: .6;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
@layer cascivo.component {
|
|
73
|
-
.sxMVlG_root {
|
|
74
|
-
color: oklch(90% .02 145);
|
|
75
|
-
font-family: ui-monospace, Cascadia Code, Source Code Pro, monospace;
|
|
76
|
-
font-size: var(--cascivo-font-size-sm, .875rem);
|
|
77
|
-
padding: var(--cascivo-space-4);
|
|
78
|
-
border-radius: var(--cascivo-radius-surface);
|
|
79
|
-
background: oklch(12% .01 250);
|
|
80
|
-
line-height: 1.6;
|
|
81
|
-
overflow-x: auto;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.sxMVlG_line {
|
|
85
|
-
gap: var(--cascivo-space-2);
|
|
86
|
-
display: flex;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.sxMVlG_prefix {
|
|
90
|
-
color: oklch(70% .15 145);
|
|
91
|
-
user-select: none;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
.sxMVlG_text {
|
|
95
|
-
flex: 1;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
.sxMVlG_cursor {
|
|
99
|
-
background: oklch(90% .02 145);
|
|
100
|
-
width: 8px;
|
|
101
|
-
height: 1em;
|
|
102
|
-
animation: 1s step-end infinite sxMVlG_cascade-cursor-blink;
|
|
103
|
-
display: inline-block;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
.sxMVlG_line[data-type="command"] .sxMVlG_text {
|
|
107
|
-
color: oklch(90% .1 250);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.sxMVlG_line[data-type="error"] .sxMVlG_text {
|
|
111
|
-
color: oklch(75% .15 22);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
.sxMVlG_line[data-type="comment"] .sxMVlG_text {
|
|
115
|
-
color: oklch(60% .02 145);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
@keyframes sxMVlG_cascade-cursor-blink {
|
|
120
|
-
0%, 100% {
|
|
121
|
-
opacity: 1;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
50% {
|
|
125
|
-
opacity: 0;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
@layer cascivo.component {
|
|
129
|
-
.GEItsa_root {
|
|
130
|
-
background: var(--cascivo-color-background);
|
|
131
|
-
border: 1px solid var(--cascivo-border-default);
|
|
132
|
-
border-radius: var(--cascivo-radius-surface);
|
|
133
|
-
flex-direction: column;
|
|
134
|
-
height: 100%;
|
|
135
|
-
min-height: 400px;
|
|
136
|
-
display: flex;
|
|
137
|
-
overflow: hidden;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
.GEItsa_messages {
|
|
141
|
-
padding: var(--cascivo-space-4);
|
|
142
|
-
gap: var(--cascivo-space-3);
|
|
143
|
-
flex-direction: column;
|
|
144
|
-
flex: 1;
|
|
145
|
-
display: flex;
|
|
146
|
-
overflow-y: auto;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
.GEItsa_message {
|
|
150
|
-
gap: var(--cascivo-space-1);
|
|
151
|
-
flex-direction: column;
|
|
152
|
-
max-width: 80%;
|
|
153
|
-
display: flex;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
.GEItsa_message[data-role="user"] {
|
|
157
|
-
align-self: flex-end;
|
|
158
|
-
align-items: flex-end;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
.GEItsa_message[data-role="assistant"] {
|
|
162
|
-
align-self: flex-start;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
.GEItsa_roleLabel {
|
|
166
|
-
font-size: var(--cascivo-font-size-xs, .75rem);
|
|
167
|
-
color: var(--cascivo-color-foreground-muted);
|
|
168
|
-
font-weight: 500;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.GEItsa_content {
|
|
172
|
-
padding: var(--cascivo-space-2) var(--cascivo-space-3);
|
|
173
|
-
border-radius: var(--cascivo-radius-control);
|
|
174
|
-
background: var(--cascivo-color-surface);
|
|
175
|
-
line-height: 1.5;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
.GEItsa_message[data-role="user"] .GEItsa_content {
|
|
179
|
-
background: var(--cascivo-color-accent);
|
|
180
|
-
color: var(--cascivo-color-accent-foreground);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
.GEItsa_inputArea {
|
|
184
|
-
gap: var(--cascivo-space-2);
|
|
185
|
-
padding: var(--cascivo-space-3);
|
|
186
|
-
border-block-start: 1px solid var(--cascivo-border-subtle);
|
|
187
|
-
background: var(--cascivo-color-surface);
|
|
188
|
-
display: flex;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
.GEItsa_textarea {
|
|
192
|
-
resize: none;
|
|
193
|
-
border: 1px solid var(--cascivo-border-default);
|
|
194
|
-
border-radius: var(--cascivo-radius-control);
|
|
195
|
-
padding: var(--cascivo-space-2) var(--cascivo-space-3);
|
|
196
|
-
font: inherit;
|
|
197
|
-
background: var(--cascivo-color-background);
|
|
198
|
-
color: var(--cascivo-color-foreground);
|
|
199
|
-
flex: 1;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
.GEItsa_sendButton {
|
|
203
|
-
padding: var(--cascivo-space-2) var(--cascivo-space-4);
|
|
204
|
-
background: var(--cascivo-color-accent);
|
|
205
|
-
color: var(--cascivo-color-accent-foreground);
|
|
206
|
-
border-radius: var(--cascivo-radius-control);
|
|
207
|
-
font: inherit;
|
|
208
|
-
cursor: pointer;
|
|
209
|
-
border: none;
|
|
210
|
-
font-weight: 500;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.GEItsa_sendButton:disabled {
|
|
214
|
-
opacity: .5;
|
|
215
|
-
cursor: not-allowed;
|
|
216
|
-
}
|
|
217
|
-
}
|