@fiestaboard/ui 6.0.3 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/components/ai/actions.d.ts +17 -0
  2. package/dist/components/ai/actions.js +33 -0
  3. package/dist/components/ai/actions.js.map +1 -0
  4. package/dist/components/ai/conversation.d.ts +44 -0
  5. package/dist/components/ai/conversation.js +91 -0
  6. package/dist/components/ai/conversation.js.map +1 -0
  7. package/dist/components/ai/loader.d.ts +18 -0
  8. package/dist/components/ai/loader.js +26 -0
  9. package/dist/components/ai/loader.js.map +1 -0
  10. package/dist/components/ai/message.d.ts +51 -0
  11. package/dist/components/ai/message.js +48 -0
  12. package/dist/components/ai/message.js.map +1 -0
  13. package/dist/components/ai/prompt-input.d.ts +61 -0
  14. package/dist/components/ai/prompt-input.js +104 -0
  15. package/dist/components/ai/prompt-input.js.map +1 -0
  16. package/dist/components/ai/shimmer.d.ts +14 -0
  17. package/dist/components/ai/shimmer.js +16 -0
  18. package/dist/components/ai/shimmer.js.map +1 -0
  19. package/dist/components/ai/spotlight.d.ts +59 -0
  20. package/dist/components/ai/spotlight.js +74 -0
  21. package/dist/components/ai/spotlight.js.map +1 -0
  22. package/dist/components/ai/suggestion.d.ts +20 -0
  23. package/dist/components/ai/suggestion.js +27 -0
  24. package/dist/components/ai/suggestion.js.map +1 -0
  25. package/dist/components/ai/task.d.ts +36 -0
  26. package/dist/components/ai/task.js +97 -0
  27. package/dist/components/ai/task.js.map +1 -0
  28. package/dist/components/ai/tool.d.ts +59 -0
  29. package/dist/components/ai/tool.js +145 -0
  30. package/dist/components/ai/tool.js.map +1 -0
  31. package/dist/index.d.ts +10 -0
  32. package/dist/index.js +11 -1
  33. package/dist/theme.css +93 -0
  34. package/package.json +1 -1
@@ -0,0 +1,17 @@
1
+ import * as React from "react";
2
+ import { Button } from "../forms/button";
3
+ /**
4
+ * Actions — the small icon affordances under an assistant turn: copy,
5
+ * retry, undo.
6
+ *
7
+ * Each {@link Action} is an icon-only button, so the `label` prop is
8
+ * required: it is the accessible name AND the tooltip. The 24px `icon-xs`
9
+ * size is the package's floor for a target (SC 2.5.8).
10
+ */
11
+ declare function Actions({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
12
+ export interface ActionProps extends Omit<React.ComponentProps<typeof Button>, "aria-label"> {
13
+ /** Accessible name and tooltip text. */
14
+ label: string;
15
+ }
16
+ declare function Action({ className, label, children, ...props }: ActionProps): React.JSX.Element;
17
+ export { Action, Actions };
@@ -0,0 +1,33 @@
1
+ "use client";
2
+ import { cn as e } from "../../lib/utils.js";
3
+ import { Button as t } from "../forms/button.js";
4
+ import { Tooltip as n, TooltipContent as r, TooltipTrigger as i } from "../overlays/tooltip.js";
5
+ import "react";
6
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
7
+ //#region src/components/ai/actions.tsx
8
+ function s({ className: t, ...n }) {
9
+ return /* @__PURE__ */ a("div", {
10
+ "data-slot": "actions",
11
+ className: e("flex items-center gap-0.5", t),
12
+ ...n
13
+ });
14
+ }
15
+ function c({ className: s, label: c, children: l, ...u }) {
16
+ return /* @__PURE__ */ o(n, { children: [/* @__PURE__ */ a(i, {
17
+ asChild: !0,
18
+ children: /* @__PURE__ */ a(t, {
19
+ "data-slot": "action",
20
+ type: "button",
21
+ variant: "ghost",
22
+ size: "icon-xs",
23
+ "aria-label": c,
24
+ className: e("text-muted-foreground hover:text-foreground", s),
25
+ ...u,
26
+ children: l
27
+ })
28
+ }), /* @__PURE__ */ a(r, { children: c })] });
29
+ }
30
+ //#endregion
31
+ export { c as Action, s as Actions };
32
+
33
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","names":[],"sources":["../../../src/components/ai/actions.tsx"],"mappings":";;;;;;;AAiBA,SAAS,EAAQ,EAAE,cAAW,GAAG,KAAsC;CACrE,OAAO,kBAAC,OAAD;EAAK,aAAU;EAAU,WAAW,EAAG,6BAA6B,CAAS;EAAG,GAAI;CAAQ,CAAA;AACrG;AAOA,SAAS,EAAO,EAAE,cAAW,UAAO,aAAU,GAAG,KAAsB;CACrE,OACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;EAAgB,SAAA;EACd,UAAA,kBAAC,GAAD;GACE,aAAU;GACV,MAAK;GACL,SAAQ;GACR,MAAK;GACL,cAAY;GACZ,WAAW,EAAG,+CAA+C,CAAS;GACtE,GAAI;GAEH;EACK,CAAA;CACM,CAAA,GAChB,kBAAC,GAAD,EAAA,UAAiB,EAAsB,CAAA,CAChC,EAAA,CAAA;AAEb"}
@@ -0,0 +1,44 @@
1
+ import * as React from "react";
2
+ import { Button } from "../forms/button";
3
+ /**
4
+ * Conversation — the scrolling transcript of a chat.
5
+ *
6
+ * Mirrors the shadcn "AI Elements" `Conversation` vocabulary (Conversation /
7
+ * ConversationContent / ConversationScrollButton) so an app written against
8
+ * that API reads the same here. Behaviour is what matters:
9
+ *
10
+ * - it is a `role="log"` region, which is how assistive technology is told
11
+ * "new entries append at the end" without re-announcing the whole list;
12
+ * - it sticks to the bottom while the user is at the bottom (a streaming
13
+ * reply keeps scrolling into view) and STOPS sticking the moment the user
14
+ * scrolls up to read — the one thing a naive `scrollIntoView` on every
15
+ * token gets wrong;
16
+ * - {@link ConversationScrollButton} appears only while the user is away
17
+ * from the bottom, and jumps back.
18
+ *
19
+ * "At the bottom" is measured, not assumed: the scroll handler updates
20
+ * state, and a ResizeObserver on the content re-pins the viewport only
21
+ * when the last measurement said the user was there. The observer runs in
22
+ * an effect but never calls setState — it scrolls the DOM — so this stays
23
+ * on the right side of the set-state-in-effect rule.
24
+ */
25
+ export interface ConversationLabels {
26
+ /** Accessible name of the log region. */
27
+ conversation: string;
28
+ /** Accessible name of the jump-to-latest button. */
29
+ scrollToBottom: string;
30
+ }
31
+ export declare const DEFAULT_CONVERSATION_LABELS: ConversationLabels;
32
+ export interface ConversationProps extends React.ComponentProps<"div"> {
33
+ labels?: Partial<ConversationLabels>;
34
+ }
35
+ declare function Conversation({ className, children, labels, onScroll, ...props }: ConversationProps): React.JSX.Element;
36
+ /** The padded stack the messages live in. */
37
+ declare function ConversationContent({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
38
+ /**
39
+ * Appears while the user has scrolled away from the newest entry. Rendered
40
+ * as nothing at all — not merely hidden — while at the bottom, so it never
41
+ * sits in the tab order as a no-op.
42
+ */
43
+ declare function ConversationScrollButton({ className, ...props }: Omit<React.ComponentProps<typeof Button>, "children">): React.JSX.Element | null;
44
+ export { Conversation, ConversationContent, ConversationScrollButton };
@@ -0,0 +1,91 @@
1
+ "use client";
2
+ import { cn as e } from "../../lib/utils.js";
3
+ import { Button as t } from "../forms/button.js";
4
+ import { ArrowDown as n } from "lucide-react";
5
+ import * as r from "react";
6
+ import { jsx as i } from "react/jsx-runtime";
7
+ //#region src/components/ai/conversation.tsx
8
+ var a = {
9
+ conversation: "Conversation",
10
+ scrollToBottom: "Jump to latest"
11
+ }, o = r.createContext(null);
12
+ function s(e) {
13
+ let t = r.useContext(o);
14
+ if (!t) throw Error(`${e} must be rendered inside <Conversation>`);
15
+ return t;
16
+ }
17
+ var c = 24;
18
+ function l({ className: t, children: n, labels: s, onScroll: l, ...u }) {
19
+ let d = {
20
+ ...a,
21
+ ...s
22
+ }, f = r.useRef(null), [p, m] = r.useState(!0), h = r.useRef(!0), g = r.useCallback(() => {
23
+ let e = f.current;
24
+ return !e || e.scrollHeight - e.scrollTop - e.clientHeight <= c;
25
+ }, []), _ = r.useCallback(() => {
26
+ let e = f.current;
27
+ e && (e.scrollTop = e.scrollHeight, h.current = !0, m(!0));
28
+ }, []), v = (e) => {
29
+ let t = g();
30
+ h.current = t, m(t), l?.(e);
31
+ };
32
+ r.useEffect(() => {
33
+ let e = f.current;
34
+ if (!e || typeof ResizeObserver > "u") return;
35
+ let t = new ResizeObserver(() => {
36
+ h.current && (e.scrollTop = e.scrollHeight);
37
+ });
38
+ for (let n of Array.from(e.children)) t.observe(n);
39
+ return () => t.disconnect();
40
+ }, []);
41
+ let y = {
42
+ isAtBottom: p,
43
+ scrollToBottom: _,
44
+ labels: d
45
+ };
46
+ return /* @__PURE__ */ i(o.Provider, {
47
+ value: y,
48
+ children: /* @__PURE__ */ i("div", {
49
+ "data-slot": "conversation",
50
+ className: e("relative flex min-h-0 flex-1 flex-col has-[[data-slot=conversation-viewport]:focus-visible]:shadow-[var(--focus-ring-shadow)]", t),
51
+ ...u,
52
+ children: /* @__PURE__ */ i("div", {
53
+ ref: f,
54
+ "data-slot": "conversation-viewport",
55
+ role: "log",
56
+ "aria-label": d.conversation,
57
+ "aria-live": "polite",
58
+ "aria-relevant": "additions text",
59
+ tabIndex: 0,
60
+ className: "min-h-0 flex-1 overflow-y-auto overscroll-contain rounded-[inherit] outline-none",
61
+ onScroll: v,
62
+ children: n
63
+ })
64
+ })
65
+ });
66
+ }
67
+ function u({ className: t, ...n }) {
68
+ return /* @__PURE__ */ i("div", {
69
+ "data-slot": "conversation-content",
70
+ className: e("flex flex-col gap-3 p-3", t),
71
+ ...n
72
+ });
73
+ }
74
+ function d({ className: r, ...a }) {
75
+ let { isAtBottom: o, scrollToBottom: c, labels: l } = s("ConversationScrollButton");
76
+ return o ? null : /* @__PURE__ */ i(t, {
77
+ "data-slot": "conversation-scroll-button",
78
+ type: "button",
79
+ variant: "outline",
80
+ size: "icon-sm",
81
+ "aria-label": l.scrollToBottom,
82
+ className: e("absolute bottom-3 left-1/2 -translate-x-1/2 rounded-full shadow-card", r),
83
+ onClick: c,
84
+ ...a,
85
+ children: /* @__PURE__ */ i(n, { "aria-hidden": "true" })
86
+ });
87
+ }
88
+ //#endregion
89
+ export { l as Conversation, u as ConversationContent, d as ConversationScrollButton, a as DEFAULT_CONVERSATION_LABELS };
90
+
91
+ //# sourceMappingURL=conversation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.js","names":[],"sources":["../../../src/components/ai/conversation.tsx"],"mappings":";;;;;;;AAsCA,IAAa,IAAkD;CAC7D,cAAc;CACd,gBAAgB;AAClB,GAQM,IAAsB,EAAM,cAA+C,IAAI;AAErF,SAAS,EAAgB,GAA6C;CACpE,IAAM,IAAM,EAAM,WAAW,CAAmB;CAChD,IAAI,CAAC,GAAK,MAAU,MAAM,GAAG,EAAU,wCAAwC;CAC/E,OAAO;AACT;AAGA,IAAM,IAAmB;AAMzB,SAAS,EAAa,EAAE,cAAW,aAAU,WAAQ,aAAU,GAAG,KAA4B;CAC5F,IAAM,IAAI;EAAE,GAAG;EAA6B,GAAG;CAAO,GAChD,IAAc,EAAM,OAA8B,IAAI,GACtD,CAAC,GAAY,KAAiB,EAAM,SAAS,EAAI,GAEjD,IAAc,EAAM,OAAO,EAAI,GAE/B,IAAU,EAAM,kBAAkB;EACtC,IAAM,IAAK,EAAY;EAEvB,OADA,CAAK,KACE,EAAG,eAAe,EAAG,YAAY,EAAG,gBAAgB;CAC7D,GAAG,CAAC,CAAC,GAEC,IAAiB,EAAM,kBAAkB;EAC7C,IAAM,IAAK,EAAY;EAClB,MACL,EAAG,YAAY,EAAG,cAClB,EAAY,UAAU,IACtB,EAAc,EAAI;CACpB,GAAG,CAAC,CAAC,GAEC,KAAgB,MAAyC;EAC7D,IAAM,IAAO,EAAQ;EAGrB,AAFA,EAAY,UAAU,GACtB,EAAc,CAAI,GAClB,IAAW,CAAK;CAClB;CAEA,EAAM,gBAAgB;EACpB,IAAM,IAAK,EAAY;EACvB,IAAI,CAAC,KAAM,OAAO,iBAAmB,KAAa;EAClD,IAAM,IAAW,IAAI,qBAAqB;GAGxC,AAAI,EAAY,YAAS,EAAG,YAAY,EAAG;EAC7C,CAAC;EACD,KAAK,IAAM,KAAS,MAAM,KAAK,EAAG,QAAQ,GAAG,EAAS,QAAQ,CAAK;EACnE,aAAa,EAAS,WAAW;CACnC,GAAG,CAAC,CAAC;CAEL,IAAM,IAAkC;EAAE;EAAY;EAAgB,QAAQ;CAAE;CAEhF,OACE,kBAAC,EAAoB,UAArB;EAAqC;EACnC,UAAA,kBAAC,OAAD;GACE,aAAU;GACV,WAAW,EAKT,iIACA,CACF;GACA,GAAI;GAEJ,UAAA,kBAAC,OAAD;IACE,KAAK;IACL,aAAU;IACV,MAAK;IACL,cAAY,EAAE;IACd,aAAU;IACV,iBAAc;IAKd,UAAU;IACV,WAAU;IACV,UAAU;IAET;GACE,CAAA;EACF,CAAA;CACuB,CAAA;AAElC;AAGA,SAAS,EAAoB,EAAE,cAAW,GAAG,KAAsC;CACjF,OAAO,kBAAC,OAAD;EAAK,aAAU;EAAuB,WAAW,EAAG,2BAA2B,CAAS;EAAG,GAAI;CAAQ,CAAA;AAChH;AAOA,SAAS,EAAyB,EAAE,cAAW,GAAG,KAAgE;CAChH,IAAM,EAAE,eAAY,mBAAgB,cAAW,EAAgB,0BAA0B;CAEzF,OADI,IAAmB,OAErB,kBAAC,GAAD;EACE,aAAU;EACV,MAAK;EACL,SAAQ;EACR,MAAK;EACL,cAAY,EAAO;EACnB,WAAW,EAAG,wEAAwE,CAAS;EAC/F,SAAS;EACT,GAAI;EAEJ,UAAA,kBAAC,GAAD,EAAW,eAAY,OAAQ,CAAA;CACzB,CAAA;AAEZ"}
@@ -0,0 +1,18 @@
1
+ import * as React from "react";
2
+ /**
3
+ * Loader — "the assistant is working" with optional text.
4
+ *
5
+ * Composes {@link Spinner}, which already swaps its rotation for a static
6
+ * ring under reduced motion, so this inherits the WCAG 2.2.2 answer rather
7
+ * than restating it. The `role="status"` lives on the Spinner when there is
8
+ * no text and on the wrapper when there is, so the message is announced
9
+ * once, not twice.
10
+ */
11
+ export interface LoaderProps extends React.ComponentProps<"div"> {
12
+ /** What is happening — "Thinking…". Announced politely. */
13
+ children?: React.ReactNode;
14
+ /** Announced when there is no visible text. */
15
+ label?: string;
16
+ }
17
+ declare function Loader({ className, children, label, ...props }: LoaderProps): React.JSX.Element;
18
+ export { Loader };
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ import { cn as e } from "../../lib/utils.js";
3
+ import { Spinner as t } from "../feedback/spinner.js";
4
+ import "react";
5
+ import { jsx as n, jsxs as r } from "react/jsx-runtime";
6
+ //#region src/components/ai/loader.tsx
7
+ function i({ className: i, children: a, label: o = "Loading", ...s }) {
8
+ let c = a != null;
9
+ return /* @__PURE__ */ r("div", {
10
+ "data-slot": "loader",
11
+ role: c ? "status" : void 0,
12
+ className: e("inline-flex items-center gap-2 text-sm text-muted-foreground", i),
13
+ ...s,
14
+ children: [/* @__PURE__ */ n(t, {
15
+ size: "sm",
16
+ label: c ? null : o
17
+ }), c ? /* @__PURE__ */ n("span", {
18
+ "data-slot": "loader-text",
19
+ children: a
20
+ }) : null]
21
+ });
22
+ }
23
+ //#endregion
24
+ export { i as Loader };
25
+
26
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","names":[],"sources":["../../../src/components/ai/loader.tsx"],"mappings":";;;;;;AAwBA,SAAS,EAAO,EAAE,cAAW,aAAU,WAAQ,WAAW,GAAG,KAAsB;CACjF,IAAM,IAAU,KAAuC;CACvD,OACE,kBAAC,OAAD;EACE,aAAU;EACV,MAAM,IAAU,WAAW,KAAA;EAC3B,WAAW,EAAG,gEAAgE,CAAS;EACvF,GAAI;EAJN,UAAA,CAME,kBAAC,GAAD;GAAS,MAAK;GAAK,OAAO,IAAU,OAAO;EAAQ,CAAA,GAClD,IAAU,kBAAC,QAAD;GAAM,aAAU;GAAe;EAAe,CAAA,IAAI,IAC1D;;AAET"}
@@ -0,0 +1,51 @@
1
+ import { type VariantProps } from "class-variance-authority";
2
+ import * as React from "react";
3
+ /**
4
+ * Message — one turn of a conversation, from the user or the assistant.
5
+ *
6
+ * `from` is the only axis. It is stamped as `data-from` on the row so the
7
+ * bubble and anything a consumer places inside can style off it
8
+ * (`group-data-[from=user]:…`) without a second prop threaded down.
9
+ *
10
+ * The assistant's turn is deliberately NOT a bubble: it is the page's own
11
+ * ground with the ink of body copy, because it carries markdown, tool
12
+ * cards and step timelines that need the full width. The user's turn is
13
+ * the bubble — short, right-aligned, on the accent surface.
14
+ */
15
+ declare const messageVariants: (props?: ({
16
+ from?: "user" | "assistant" | null | undefined;
17
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
18
+ export interface MessageProps extends React.ComponentProps<"div">, VariantProps<typeof messageVariants> {
19
+ from: "user" | "assistant";
20
+ }
21
+ declare function Message({ className, from, ...props }: MessageProps): React.JSX.Element;
22
+ declare const messageContentVariants: (props?: ({
23
+ from?: "user" | "assistant" | null | undefined;
24
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
25
+ export interface MessageContentProps extends React.ComponentProps<"div">, VariantProps<typeof messageContentVariants> {
26
+ }
27
+ /**
28
+ * The body of a turn. Reads `from` off the nearest {@link Message} when not
29
+ * given, so the common case is `<Message from="user"><MessageContent>…`.
30
+ */
31
+ declare function MessageContent({ className, from, ...props }: MessageContentProps): React.JSX.Element;
32
+ export interface MessageAvatarProps extends React.ComponentProps<"span"> {
33
+ /**
34
+ * Fallback initial when no child glyph is given. One character is used.
35
+ */
36
+ name?: string;
37
+ /**
38
+ * Decorative by default: the turn's `from` is already conveyed by
39
+ * position and content, and a screen reader announcing "assistant
40
+ * avatar" before every reply is noise. Pass `decorative={false}` and an
41
+ * `aria-label` when the avatar is the only thing naming the speaker.
42
+ */
43
+ decorative?: boolean;
44
+ }
45
+ /**
46
+ * A small round mark beside a turn: an icon child, or the first letter of
47
+ * `name`. Not an image component — chat avatars here are glyphs, and the
48
+ * package ships no image loading.
49
+ */
50
+ declare function MessageAvatar({ className, name, decorative, children, ...props }: MessageAvatarProps): React.JSX.Element;
51
+ export { Message, MessageAvatar, MessageContent, messageContentVariants, messageVariants };
@@ -0,0 +1,48 @@
1
+ "use client";
2
+ import { cn as e } from "../../lib/utils.js";
3
+ import "react";
4
+ import { jsx as t } from "react/jsx-runtime";
5
+ import { cva as n } from "class-variance-authority";
6
+ //#region src/components/ai/message.tsx
7
+ var r = n("group flex w-full gap-2", {
8
+ variants: { from: {
9
+ user: "flex-row-reverse",
10
+ assistant: "flex-row"
11
+ } },
12
+ defaultVariants: { from: "assistant" }
13
+ });
14
+ function i({ className: n, from: i, ...a }) {
15
+ return /* @__PURE__ */ t("div", {
16
+ "data-slot": "message",
17
+ "data-from": i,
18
+ className: e(r({ from: i }), n),
19
+ ...a
20
+ });
21
+ }
22
+ var a = n("min-w-0 text-sm leading-relaxed", {
23
+ variants: { from: {
24
+ user: "max-w-[85%] rounded-xl rounded-br-sm bg-accent px-3 py-2 text-accent-foreground",
25
+ assistant: "flex-1 text-foreground"
26
+ } },
27
+ defaultVariants: { from: "assistant" }
28
+ });
29
+ function o({ className: n, from: r, ...i }) {
30
+ return /* @__PURE__ */ t("div", {
31
+ "data-slot": "message-content",
32
+ className: e(a({ from: r }), r === void 0 && "group-data-[from=user]:max-w-[85%] group-data-[from=user]:rounded-xl group-data-[from=user]:rounded-br-sm group-data-[from=user]:bg-accent group-data-[from=user]:px-3 group-data-[from=user]:py-2 group-data-[from=user]:text-accent-foreground", n),
33
+ ...i
34
+ });
35
+ }
36
+ function s({ className: n, name: r, decorative: i = !0, children: a, ...o }) {
37
+ return /* @__PURE__ */ t("span", {
38
+ "data-slot": "message-avatar",
39
+ "aria-hidden": i || void 0,
40
+ className: e("inline-flex size-6 shrink-0 items-center justify-center rounded-full bg-muted text-xs font-medium text-muted-foreground", "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5", n),
41
+ ...o,
42
+ children: a ?? (r ? r.trim().charAt(0).toUpperCase() : null)
43
+ });
44
+ }
45
+ //#endregion
46
+ export { i as Message, s as MessageAvatar, o as MessageContent, a as messageContentVariants, r as messageVariants };
47
+
48
+ //# sourceMappingURL=message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.js","names":[],"sources":["../../../src/components/ai/message.tsx"],"mappings":";;;;;;AAmBA,IAAM,IAAkB,EAAI,2BAA2B;CACrD,UAAU,EACR,MAAM;EACJ,MAAM;EACN,WAAW;CACb,EACF;CACA,iBAAiB,EACf,MAAM,YACR;AACF,CAAC;AAMD,SAAS,EAAQ,EAAE,cAAW,SAAM,GAAG,KAAuB;CAC5D,OAAO,kBAAC,OAAD;EAAK,aAAU;EAAU,aAAW;EAAM,WAAW,EAAG,EAAgB,EAAE,QAAK,CAAC,GAAG,CAAS;EAAG,GAAI;CAAQ,CAAA;AACpH;AAEA,IAAM,IAAyB,EAAI,mCAAmC;CACpE,UAAU,EACR,MAAM;EACJ,MAAM;EACN,WAAW;CACb,EACF;CACA,iBAAiB,EACf,MAAM,YACR;AACF,CAAC;AAQD,SAAS,EAAe,EAAE,cAAW,SAAM,GAAG,KAA8B;CAC1E,OACE,kBAAC,OAAD;EACE,aAAU;EACV,WAAW,EACT,EAAuB,EAAE,QAAK,CAAC,GAC/B,MAAS,KAAA,KACP,oPACF,CACF;EACA,GAAI;CACL,CAAA;AAEL;AAqBA,SAAS,EAAc,EAAE,cAAW,SAAM,gBAAa,IAAM,aAAU,GAAG,KAA6B;CACrG,OACE,kBAAC,QAAD;EACE,aAAU;EACV,eAAa,KAAc,KAAA;EAC3B,WAAW,EACT,2HACA,uFACA,CACF;EACA,GAAI;EAEH,UAAA,MAAa,IAAO,EAAK,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI;CACvD,CAAA;AAEV"}
@@ -0,0 +1,61 @@
1
+ import * as React from "react";
2
+ import { Button } from "../forms/button";
3
+ import { Textarea } from "../forms/textarea";
4
+ /**
5
+ * PromptInput — the composer at the bottom of a chat.
6
+ *
7
+ * Follows the "AI Elements" composition (PromptInput / PromptInputTextarea
8
+ * / PromptInputToolbar / PromptInputTools / PromptInputSubmit) with one
9
+ * shared `status`:
10
+ *
11
+ * ready the user may send
12
+ * submitted sent, nothing streamed yet
13
+ * streaming a reply is arriving — the submit button becomes Stop
14
+ * error the last send failed; sending is allowed again
15
+ *
16
+ * Keyboard: Enter sends, Shift+Enter inserts a newline (the convention
17
+ * every chat product has settled on). IME composition is respected — an
18
+ * Enter that commits a Japanese/Chinese candidate never sends.
19
+ *
20
+ * Data in, events out: the form's `onSubmit` fires with the native event;
21
+ * the consumer owns the value and clears it. The family never fetches.
22
+ */
23
+ export type PromptInputStatus = "ready" | "submitted" | "streaming" | "error";
24
+ export interface PromptInputLabels {
25
+ /** Accessible name of the send button. */
26
+ send: string;
27
+ /** Accessible name of the stop button (shown while streaming). */
28
+ stop: string;
29
+ }
30
+ export declare const DEFAULT_PROMPT_INPUT_LABELS: PromptInputLabels;
31
+ export interface PromptInputProps extends React.ComponentProps<"form"> {
32
+ status?: PromptInputStatus;
33
+ labels?: Partial<PromptInputLabels>;
34
+ }
35
+ declare function PromptInput({ className, status, labels, ...props }: PromptInputProps): React.JSX.Element;
36
+ export interface PromptInputTextareaProps extends React.ComponentProps<typeof Textarea> {
37
+ /** Rows shown before the textarea grows with its content. */
38
+ minRows?: number;
39
+ /** Rows at which growth stops and the textarea scrolls. */
40
+ maxRows?: number;
41
+ }
42
+ /**
43
+ * Enter submits the enclosing form; Shift+Enter is a newline. The textarea
44
+ * grows with its content between `minRows` and `maxRows`, measured from
45
+ * the real scroll height so a pasted paragraph is fully visible.
46
+ */
47
+ declare function PromptInputTextarea({ className, minRows, maxRows, onKeyDown, onInput, ref, ...props }: PromptInputTextareaProps): React.JSX.Element;
48
+ /** The row under the textarea: tools on the left, submit on the right. */
49
+ declare function PromptInputToolbar({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
50
+ /** The left-hand group of the toolbar: model picker, attachments, modes. */
51
+ declare function PromptInputTools({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
52
+ export interface PromptInputSubmitProps extends Omit<React.ComponentProps<typeof Button>, "children" | "type"> {
53
+ /** Called instead of submitting while `status` is `streaming`. */
54
+ onStop?: () => void;
55
+ }
56
+ /**
57
+ * Send while ready, Stop while streaming. The Stop form is `type="button"`
58
+ * so a click can never accidentally submit the form it sits in.
59
+ */
60
+ declare function PromptInputSubmit({ className, onStop, disabled, ...props }: PromptInputSubmitProps): React.JSX.Element;
61
+ export { PromptInput, PromptInputSubmit, PromptInputTextarea, PromptInputToolbar, PromptInputTools };
@@ -0,0 +1,104 @@
1
+ "use client";
2
+ import { cn as e } from "../../lib/utils.js";
3
+ import { Button as t } from "../forms/button.js";
4
+ import { Textarea as n } from "../forms/textarea.js";
5
+ import { ArrowUp as r, Square as i } from "lucide-react";
6
+ import * as a from "react";
7
+ import { jsx as o } from "react/jsx-runtime";
8
+ //#region src/components/ai/prompt-input.tsx
9
+ var s = {
10
+ send: "Send",
11
+ stop: "Stop"
12
+ }, c = a.createContext({
13
+ status: "ready",
14
+ labels: s
15
+ });
16
+ function l({ className: t, status: n = "ready", labels: r, ...i }) {
17
+ let a = {
18
+ status: n,
19
+ labels: {
20
+ ...s,
21
+ ...r
22
+ }
23
+ };
24
+ return /* @__PURE__ */ o(c.Provider, {
25
+ value: a,
26
+ children: /* @__PURE__ */ o("form", {
27
+ "data-slot": "prompt-input",
28
+ "data-status": n,
29
+ className: e("flex w-full flex-col rounded-xl border bg-card shadow-card transition-[box-shadow,border-color] duration-base", "focus-within:border-ring focus-within:shadow-[var(--focus-ring-shadow)]", t),
30
+ ...i
31
+ })
32
+ });
33
+ }
34
+ function u({ className: t, minRows: r = 1, maxRows: i = 6, onKeyDown: s, onInput: c, ref: l, ...u }) {
35
+ let d = a.useRef(null), f = (e) => {
36
+ d.current = e, typeof l == "function" ? l(e) : l && (l.current = e);
37
+ }, p = () => {
38
+ let e = d.current;
39
+ if (!e) return;
40
+ let t = Number.parseFloat(getComputedStyle(e).lineHeight) || 20;
41
+ e.style.height = "auto";
42
+ let n = t * i;
43
+ e.style.height = `${Math.min(e.scrollHeight, n)}px`, e.style.overflowY = e.scrollHeight > n ? "auto" : "hidden";
44
+ };
45
+ return /* @__PURE__ */ o(n, {
46
+ ref: f,
47
+ "data-slot": "prompt-input-textarea",
48
+ rows: r,
49
+ className: e("min-h-0 resize-none border-0 bg-transparent px-3 py-2.5 shadow-none", "focus-visible:border-transparent focus-visible:ring-0 hover:border-transparent", t),
50
+ onInput: (e) => {
51
+ p(), c?.(e);
52
+ },
53
+ onKeyDown: (e) => {
54
+ s?.(e), !e.defaultPrevented && e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing && (e.preventDefault(), e.currentTarget.form?.requestSubmit());
55
+ },
56
+ ...u
57
+ });
58
+ }
59
+ function d({ className: t, ...n }) {
60
+ return /* @__PURE__ */ o("div", {
61
+ "data-slot": "prompt-input-toolbar",
62
+ className: e("flex items-center justify-between gap-2 px-2 pb-2", t),
63
+ ...n
64
+ });
65
+ }
66
+ function f({ className: t, ...n }) {
67
+ return /* @__PURE__ */ o("div", {
68
+ "data-slot": "prompt-input-tools",
69
+ className: e("flex items-center gap-1", t),
70
+ ...n
71
+ });
72
+ }
73
+ function p({ className: n, onStop: s, disabled: l, ...u }) {
74
+ let { status: d, labels: f } = a.useContext(c);
75
+ return d === "streaming" ? /* @__PURE__ */ o(t, {
76
+ "data-slot": "prompt-input-submit",
77
+ "data-status": d,
78
+ type: "button",
79
+ size: "icon-sm",
80
+ variant: "outline",
81
+ "aria-label": f.stop,
82
+ className: e("rounded-full", n),
83
+ onClick: s,
84
+ ...u,
85
+ children: /* @__PURE__ */ o(i, {
86
+ "aria-hidden": "true",
87
+ className: "size-3.5 fill-current"
88
+ })
89
+ }) : /* @__PURE__ */ o(t, {
90
+ "data-slot": "prompt-input-submit",
91
+ "data-status": d,
92
+ type: "submit",
93
+ size: "icon-sm",
94
+ "aria-label": f.send,
95
+ disabled: l || d === "submitted",
96
+ className: e("rounded-full", n),
97
+ ...u,
98
+ children: /* @__PURE__ */ o(r, { "aria-hidden": "true" })
99
+ });
100
+ }
101
+ //#endregion
102
+ export { s as DEFAULT_PROMPT_INPUT_LABELS, l as PromptInput, p as PromptInputSubmit, u as PromptInputTextarea, d as PromptInputToolbar, f as PromptInputTools };
103
+
104
+ //# sourceMappingURL=prompt-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-input.js","names":[],"sources":["../../../src/components/ai/prompt-input.tsx"],"mappings":";;;;;;;;AAsCA,IAAa,IAAiD;CAC5D,MAAM;CACN,MAAM;AACR,GAOM,IAAqB,EAAM,cAAuC;CACtE,QAAQ;CACR,QAAQ;AACV,CAAC;AAOD,SAAS,EAAY,EAAE,cAAW,YAAS,SAAS,WAAQ,GAAG,KAA2B;CAExF,IAAM,IAAiC;EAAE;EAAQ,QAAQ;GAD7C,GAAG;GAA6B,GAAG;EACU;CAAE;CAC3D,OACE,kBAAC,EAAmB,UAApB;EAAoC;EAClC,UAAA,kBAAC,QAAD;GACE,aAAU;GACV,eAAa;GACb,WAAW,EACT,iHACA,2EACA,CACF;GACA,GAAI;EACL,CAAA;CAC0B,CAAA;AAEjC;AAcA,SAAS,EAAoB,EAC3B,cACA,aAAU,GACV,aAAU,GACV,cACA,YACA,QACA,GAAG,KACwB;CAC3B,IAAM,IAAW,EAAM,OAAmC,IAAI,GAExD,KAAW,MAAqC;EAEpD,AADA,EAAS,UAAU,GACf,OAAO,KAAQ,aAAY,EAAI,CAAI,IAC9B,MAAK,EAA4D,UAAU;CACtF,GAEM,UAAe;EACnB,IAAM,IAAK,EAAS;EACpB,IAAI,CAAC,GAAI;EACT,IAAM,IAAO,OAAO,WAAW,iBAAiB,CAAE,CAAC,CAAC,UAAU,KAAK;EACnE,EAAG,MAAM,SAAS;EAClB,IAAM,IAAM,IAAO;EAEnB,AADA,EAAG,MAAM,SAAS,GAAG,KAAK,IAAI,EAAG,cAAc,CAAG,EAAE,KACpD,EAAG,MAAM,YAAY,EAAG,eAAe,IAAM,SAAS;CACxD;CAEA,OACE,kBAAC,GAAD;EACE,KAAK;EACL,aAAU;EACV,MAAM;EACN,WAAW,EACT,uEACA,kFACA,CACF;EACA,UAAU,MAAU;GAElB,AADA,EAAO,GACP,IAAU,CAAK;EACjB;EACA,YAAY,MAAU;GACpB,IAAY,CAAK,GACb,GAAM,oBACN,EAAM,QAAQ,WAAW,CAAC,EAAM,YAAY,CAAC,EAAM,YAAY,gBACjE,EAAM,eAAe,GACrB,EAAM,cAAc,MAAM,cAAc;EAE5C;EACA,GAAI;CACL,CAAA;AAEL;AAGA,SAAS,EAAmB,EAAE,cAAW,GAAG,KAAsC;CAChF,OACE,kBAAC,OAAD;EACE,aAAU;EACV,WAAW,EAAG,qDAAqD,CAAS;EAC5E,GAAI;CACL,CAAA;AAEL;AAGA,SAAS,EAAiB,EAAE,cAAW,GAAG,KAAsC;CAC9E,OAAO,kBAAC,OAAD;EAAK,aAAU;EAAqB,WAAW,EAAG,2BAA2B,CAAS;EAAG,GAAI;CAAQ,CAAA;AAC9G;AAWA,SAAS,EAAkB,EAAE,cAAW,WAAQ,aAAU,GAAG,KAAiC;CAC5F,IAAM,EAAE,WAAQ,cAAW,EAAM,WAAW,CAAkB;CAmB9D,OAlBkB,MAAW,cAGzB,kBAAC,GAAD;EACE,aAAU;EACV,eAAa;EACb,MAAK;EACL,MAAK;EACL,SAAQ;EACR,cAAY,EAAO;EACnB,WAAW,EAAG,gBAAgB,CAAS;EACvC,SAAS;EACT,GAAI;EAEJ,UAAA,kBAAC,GAAD;GAAQ,eAAY;GAAO,WAAU;EAAyB,CAAA;CACxD,CAAA,IAIV,kBAAC,GAAD;EACE,aAAU;EACV,eAAa;EACb,MAAK;EACL,MAAK;EACL,cAAY,EAAO;EACnB,UAAU,KAAY,MAAW;EACjC,WAAW,EAAG,gBAAgB,CAAS;EACvC,GAAI;EAEJ,UAAA,kBAAC,GAAD,EAAS,eAAY,OAAQ,CAAA;CACvB,CAAA;AAEZ"}
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ /**
3
+ * Shimmer — text with a light sweep, for a status line that is still in
4
+ * progress ("Running create_page…").
5
+ *
6
+ * The sweep is `.ai-shimmer` in theme.css: a gradient clipped to the text,
7
+ * moving on `ai-shimmer` keyframes. Under reduced motion the class pins
8
+ * the gradient's position so the text is a plain, fully legible
9
+ * muted-foreground — an infinite sweep is exactly what WCAG 2.2.2 (Pause,
10
+ * Stop, Hide) exists for, and the global 1ms backstop alone would freeze
11
+ * it at an arbitrary frame.
12
+ */
13
+ declare function Shimmer({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
14
+ export { Shimmer };
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { cn as e } from "../../lib/utils.js";
3
+ import "react";
4
+ import { jsx as t } from "react/jsx-runtime";
5
+ //#region src/components/ai/shimmer.tsx
6
+ function n({ className: n, ...r }) {
7
+ return /* @__PURE__ */ t("span", {
8
+ "data-slot": "shimmer",
9
+ className: e("ai-shimmer text-sm", n),
10
+ ...r
11
+ });
12
+ }
13
+ //#endregion
14
+ export { n as Shimmer };
15
+
16
+ //# sourceMappingURL=shimmer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shimmer.js","names":[],"sources":["../../../src/components/ai/shimmer.tsx"],"mappings":";;;;;AAiBA,SAAS,EAAQ,EAAE,cAAW,GAAG,KAAuC;CACtE,OAAO,kBAAC,QAAD;EAAM,aAAU;EAAU,WAAW,EAAG,sBAAsB,CAAS;EAAG,GAAI;CAAQ,CAAA;AAC/F"}
@@ -0,0 +1,59 @@
1
+ import { type VariantProps } from "class-variance-authority";
2
+ import * as React from "react";
3
+ /**
4
+ * Spotlight — the visual language for "the assistant is working HERE".
5
+ *
6
+ * Three presentational parts an app positions itself (the package knows
7
+ * nothing about the app's DOM, routes or which element is meant):
8
+ *
9
+ * - {@link SpotlightRing} — a ring drawn around a target rectangle, with a
10
+ * tone: `driving` (the assistant is acting on this), `landed` (the change
11
+ * arrived), `error`. `aria-hidden`: the ring is for sighted users; the
12
+ * caption and the app's own live regions carry the same information.
13
+ * - {@link SpotlightCaption} — a small bubble that says what is happening
14
+ * ("Typing the name…"), a polite live region, with an optional slot for
15
+ * controls (Stop, Approve/Deny).
16
+ * - {@link GhostValue} — a value being "typed into" a control the app must
17
+ * not actually mutate: renders the typed prefix with a caret at
18
+ * `progress`, or the whole value as a badge for controls with no text
19
+ * box (a switch, a select). `aria-hidden`: the real control keeps its
20
+ * accessible value; the caption narrates the change.
21
+ *
22
+ * The pulse and caret are `.ai-spotlight-pulse` / `.ai-caret` in
23
+ * theme.css, each with a reduced-motion pose (a static ring, a solid
24
+ * caret) rather than an arbitrary frozen frame.
25
+ *
26
+ * The app positions these with inline `style` (a measured rect), which is
27
+ * why none of them carries a position of its own: they are `absolute`
28
+ * boxes in whatever coordinate space the consumer puts them in.
29
+ */
30
+ export type SpotlightTone = "driving" | "landed" | "error";
31
+ declare const spotlightRingVariants: (props?: ({
32
+ tone?: "error" | "driving" | "landed" | null | undefined;
33
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
34
+ export interface SpotlightRingProps extends React.ComponentProps<"div">, VariantProps<typeof spotlightRingVariants> {
35
+ tone?: SpotlightTone;
36
+ }
37
+ declare function SpotlightRing({ className, tone, ...props }: SpotlightRingProps): React.JSX.Element;
38
+ export interface SpotlightCaptionProps extends React.ComponentProps<"div"> {
39
+ tone?: SpotlightTone;
40
+ /** Controls rendered after the text: Stop, Approve, Deny. */
41
+ controls?: React.ReactNode;
42
+ }
43
+ declare function SpotlightCaption({ className, tone, controls, children, ...props }: SpotlightCaptionProps): React.JSX.Element;
44
+ export interface GhostValueProps extends Omit<React.ComponentProps<"span">, "children"> {
45
+ /** The full value being revealed. */
46
+ value: string;
47
+ /** 0..1 — how much of `value` is shown; 1 shows all of it. */
48
+ progress?: number;
49
+ /**
50
+ * `replica` overlays a text box and shows the typed prefix with a caret;
51
+ * `badge` sits beside a control with no text (a switch, a select) and
52
+ * shows the whole value at once.
53
+ */
54
+ variant?: "replica" | "badge";
55
+ }
56
+ /** The number of characters visible at `progress`, never past the end. */
57
+ export declare function revealedLength(value: string, progress: number): number;
58
+ declare function GhostValue({ className, value, progress, variant, ...props }: GhostValueProps): React.JSX.Element;
59
+ export { GhostValue, SpotlightCaption, SpotlightRing, spotlightRingVariants };