@page-speed/agent-everywhere 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1091,8 +1091,27 @@ interface PromptInputProps {
1091
1091
  inputClassName?: string;
1092
1092
  /** Variant styling */
1093
1093
  variant?: 'default' | 'minimal' | 'bordered';
1094
+ /**
1095
+ * Minimum number of visible text rows. Default 1 (grows as the user types).
1096
+ */
1097
+ minRows?: number;
1098
+ /**
1099
+ * Maximum number of visible text rows before the textarea scrolls internally
1100
+ * instead of growing further. Default 6.
1101
+ */
1102
+ maxRows?: number;
1094
1103
  }
1095
- declare const PromptInput: react.ForwardRefExoticComponent<PromptInputProps & react.RefAttributes<HTMLInputElement>>;
1104
+ /**
1105
+ * Conversational prompt input.
1106
+ *
1107
+ * Behaves like a standard AI chat input: it is a multi-line, auto-growing
1108
+ * textarea where **Enter submits** and **Shift+Enter inserts a newline**. The
1109
+ * textarea grows with content up to `maxRows`, then scrolls internally.
1110
+ *
1111
+ * (Previously this was a single-line `<input>`, which made Shift+Enter a no-op
1112
+ * and prevented multi-line messages entirely.)
1113
+ */
1114
+ declare const PromptInput: react.ForwardRefExoticComponent<PromptInputProps & react.RefAttributes<HTMLTextAreaElement>>;
1096
1115
 
1097
1116
  interface MultimodalInputProps {
1098
1117
  /** Current input value */
package/dist/index.d.ts CHANGED
@@ -1091,8 +1091,27 @@ interface PromptInputProps {
1091
1091
  inputClassName?: string;
1092
1092
  /** Variant styling */
1093
1093
  variant?: 'default' | 'minimal' | 'bordered';
1094
+ /**
1095
+ * Minimum number of visible text rows. Default 1 (grows as the user types).
1096
+ */
1097
+ minRows?: number;
1098
+ /**
1099
+ * Maximum number of visible text rows before the textarea scrolls internally
1100
+ * instead of growing further. Default 6.
1101
+ */
1102
+ maxRows?: number;
1094
1103
  }
1095
- declare const PromptInput: react.ForwardRefExoticComponent<PromptInputProps & react.RefAttributes<HTMLInputElement>>;
1104
+ /**
1105
+ * Conversational prompt input.
1106
+ *
1107
+ * Behaves like a standard AI chat input: it is a multi-line, auto-growing
1108
+ * textarea where **Enter submits** and **Shift+Enter inserts a newline**. The
1109
+ * textarea grows with content up to `maxRows`, then scrolls internally.
1110
+ *
1111
+ * (Previously this was a single-line `<input>`, which made Shift+Enter a no-op
1112
+ * and prevented multi-line messages entirely.)
1113
+ */
1114
+ declare const PromptInput: react.ForwardRefExoticComponent<PromptInputProps & react.RefAttributes<HTMLTextAreaElement>>;
1096
1115
 
1097
1116
  interface MultimodalInputProps {
1098
1117
  /** Current input value */
package/dist/index.js CHANGED
@@ -2,9 +2,10 @@
2
2
  import { clsx } from 'clsx';
3
3
  import { twMerge } from 'tailwind-merge';
4
4
  import * as React4 from 'react';
5
- import { createContext, forwardRef, useCallback, useRef, useState, useEffect, useReducer, useMemo, useContext } from 'react';
5
+ import { createContext, forwardRef, useRef, useImperativeHandle, useCallback, useLayoutEffect, useState, useEffect, useReducer, useMemo, useContext } from 'react';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
  import { AnimatePresence, motion } from 'motion/react';
8
+ import { Markdown } from '@page-speed/markdown-to-jsx';
8
9
  import { SendIcon, PaperclipIcon, FileTextIcon, MicIcon, ImageIcon, XIcon, SearchIcon, UploadIcon, FileIcon, UserCircleIcon, CheckIcon, SparklesIcon, BookmarkIcon, InfoIcon, CheckCircle2Icon, AlertTriangleIcon, LightbulbIcon, BrainIcon, ChevronDownIcon, ZapIcon, CopyIcon, ThumbsUpIcon, ThumbsDownIcon, BotIcon, UserIcon, DownloadIcon, MinusIcon, TrendingDownIcon, TrendingUpIcon, ChevronUpIcon, ArrowUpDownIcon, LinkIcon, PlayIcon, ExternalLinkIcon, WandIcon, LayoutGridIcon, Grid3X3Icon, ArrowUpRightIcon, ShuffleIcon, SkipForwardIcon, ChevronLeftIcon, ChevronRightIcon, XCircleIcon, HelpCircleIcon, Minimize2Icon, Maximize2Icon, RotateCcwIcon, MessageSquareIcon, GripVerticalIcon, PanelLeftOpenIcon, PanelLeftCloseIcon, CheckCircleIcon, AlertCircleIcon, MoreHorizontalIcon, ArrowLeftIcon, MoreVerticalIcon, Loader2Icon, ArrowRightIcon, AlignLeftIcon, ListIcon, HashIcon, TypeIcon, ClockIcon, CoinsIcon, ActivityIcon, ArrowUpIcon, ArrowDownIcon } from 'lucide-react';
9
10
  import { Slot } from '@radix-ui/react-slot';
10
11
  import { cva } from 'class-variance-authority';
@@ -980,7 +981,32 @@ function MessageBubble({ role, children, className, unstyled }) {
980
981
  }
981
982
  );
982
983
  }
983
- function MessageContent({ children, className }) {
984
+ var PROSE_CLASSES = cn(
985
+ "text-sm leading-relaxed",
986
+ "[&_p]:my-1.5 first:[&_p]:mt-0 last:[&_p]:mb-0",
987
+ "[&_ul]:my-1.5 [&_ul]:list-disc [&_ul]:pl-5",
988
+ "[&_ol]:my-1.5 [&_ol]:list-decimal [&_ol]:pl-5",
989
+ "[&_li]:my-0.5",
990
+ "[&_h1]:mt-2 [&_h1]:mb-1 [&_h1]:text-base [&_h1]:font-semibold",
991
+ "[&_h2]:mt-2 [&_h2]:mb-1 [&_h2]:text-sm [&_h2]:font-semibold",
992
+ "[&_h3]:mt-2 [&_h3]:mb-1 [&_h3]:text-sm [&_h3]:font-semibold",
993
+ "[&_strong]:font-semibold",
994
+ "[&_a]:underline [&_a]:underline-offset-2",
995
+ "[&_code]:rounded [&_code]:bg-black/10 [&_code]:px-1 [&_code]:py-0.5 [&_code]:text-[0.85em]",
996
+ "[&_pre]:my-1.5 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-black/10 [&_pre]:p-2 [&_pre]:text-xs",
997
+ "[&_pre_code]:bg-transparent [&_pre_code]:p-0",
998
+ "[&_blockquote]:border-l-2 [&_blockquote]:border-current/30 [&_blockquote]:pl-3 [&_blockquote]:opacity-90",
999
+ "[&_hr]:my-2 [&_hr]:border-current/20",
1000
+ "whitespace-normal"
1001
+ );
1002
+ function MessageContent({
1003
+ children,
1004
+ className,
1005
+ markdown = true
1006
+ }) {
1007
+ if (markdown && typeof children === "string") {
1008
+ return /* @__PURE__ */ jsx(Markdown, { className: cn(PROSE_CLASSES, className), children });
1009
+ }
984
1010
  return /* @__PURE__ */ jsx("div", { className: cn("text-sm leading-relaxed whitespace-pre-wrap", className), children });
985
1011
  }
986
1012
  function MessageContainer({ role, children, className }) {
@@ -1056,23 +1082,6 @@ function StatusBadge({
1056
1082
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-[10px]", children: displayLabel })
1057
1083
  ] });
1058
1084
  }
1059
- var Input = React4.forwardRef(
1060
- ({ className, type, ...props }, ref) => {
1061
- return /* @__PURE__ */ jsx(
1062
- "input",
1063
- {
1064
- type,
1065
- className: cn(
1066
- "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
1067
- className
1068
- ),
1069
- ref,
1070
- ...props
1071
- }
1072
- );
1073
- }
1074
- );
1075
- Input.displayName = "Input";
1076
1085
  var buttonVariants = cva(
1077
1086
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1078
1087
  {
@@ -1112,6 +1121,8 @@ var Button = React4.forwardRef(
1112
1121
  }
1113
1122
  );
1114
1123
  Button.displayName = "Button";
1124
+ var LINE_HEIGHT_PX = 20;
1125
+ var VERTICAL_PADDING_PX = 8;
1115
1126
  var PromptInput = forwardRef(
1116
1127
  ({
1117
1128
  value,
@@ -1127,11 +1138,28 @@ var PromptInput = forwardRef(
1127
1138
  rightActions,
1128
1139
  className,
1129
1140
  inputClassName,
1130
- variant = "default"
1141
+ variant = "default",
1142
+ minRows = 1,
1143
+ maxRows = 6
1131
1144
  }, ref) => {
1145
+ const textareaRef = useRef(null);
1146
+ useImperativeHandle(ref, () => textareaRef.current);
1147
+ const resize = useCallback(() => {
1148
+ const el = textareaRef.current;
1149
+ if (!el) return;
1150
+ el.style.height = "auto";
1151
+ const maxHeight = maxRows * LINE_HEIGHT_PX + VERTICAL_PADDING_PX;
1152
+ const minHeight = minRows * LINE_HEIGHT_PX + VERTICAL_PADDING_PX;
1153
+ const next = Math.min(Math.max(el.scrollHeight, minHeight), maxHeight);
1154
+ el.style.height = `${next}px`;
1155
+ el.style.overflowY = el.scrollHeight > maxHeight ? "auto" : "hidden";
1156
+ }, [maxRows, minRows]);
1157
+ useLayoutEffect(() => {
1158
+ resize();
1159
+ }, [value, resize]);
1132
1160
  const handleSubmit = useCallback(
1133
1161
  (e) => {
1134
- e.preventDefault();
1162
+ e?.preventDefault();
1135
1163
  if (!value.trim() || disabled || loading) return;
1136
1164
  onSubmit();
1137
1165
  },
@@ -1141,7 +1169,7 @@ var PromptInput = forwardRef(
1141
1169
  (e) => {
1142
1170
  if (e.key === "Enter" && !e.shiftKey) {
1143
1171
  e.preventDefault();
1144
- handleSubmit(e);
1172
+ handleSubmit();
1145
1173
  }
1146
1174
  },
1147
1175
  [handleSubmit]
@@ -1152,48 +1180,65 @@ var PromptInput = forwardRef(
1152
1180
  bordered: "border rounded-lg px-3 py-2.5"
1153
1181
  };
1154
1182
  const inputVariantStyles = {
1155
- default: "h-9 border-0 bg-transparent shadow-none focus-visible:ring-0",
1156
- minimal: "h-8 border-0 bg-transparent shadow-none focus-visible:ring-0 px-0",
1157
- bordered: "h-9 border-0 bg-muted/50 shadow-none focus-visible:ring-0"
1183
+ default: "bg-transparent",
1184
+ minimal: "bg-transparent px-0",
1185
+ bordered: "bg-muted/50"
1158
1186
  };
1187
+ return /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, className: cn(variantStyles[variant], className), children: /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
1188
+ leftActions,
1189
+ /* @__PURE__ */ jsx(
1190
+ "textarea",
1191
+ {
1192
+ ref: textareaRef,
1193
+ value,
1194
+ onChange: (e) => onChange(e.target.value),
1195
+ onKeyDown: handleKeyDown,
1196
+ placeholder,
1197
+ disabled: disabled || loading,
1198
+ autoFocus,
1199
+ rows: minRows,
1200
+ className: cn(
1201
+ "flex-1 resize-none border-0 px-0 py-1 text-sm leading-5 shadow-none",
1202
+ "placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0",
1203
+ "disabled:cursor-not-allowed disabled:opacity-50",
1204
+ inputVariantStyles[variant],
1205
+ inputClassName
1206
+ )
1207
+ }
1208
+ ),
1209
+ rightActions,
1210
+ showSendButton && /* @__PURE__ */ jsx(
1211
+ Button,
1212
+ {
1213
+ type: "submit",
1214
+ size: "sm",
1215
+ variant: variant === "minimal" ? "ghost" : "outline",
1216
+ disabled: !value.trim() || disabled || loading,
1217
+ className: "size-8 shrink-0 p-0",
1218
+ children: sendButtonContent || /* @__PURE__ */ jsx(SendIcon, { className: "size-4" })
1219
+ }
1220
+ )
1221
+ ] }) });
1222
+ }
1223
+ );
1224
+ PromptInput.displayName = "PromptInput";
1225
+ var Input = React4.forwardRef(
1226
+ ({ className, type, ...props }, ref) => {
1159
1227
  return /* @__PURE__ */ jsx(
1160
- "form",
1228
+ "input",
1161
1229
  {
1162
- onSubmit: handleSubmit,
1163
- className: cn(variantStyles[variant], className),
1164
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1165
- leftActions,
1166
- /* @__PURE__ */ jsx(
1167
- Input,
1168
- {
1169
- ref,
1170
- value,
1171
- onChange: (e) => onChange(e.target.value),
1172
- onKeyDown: handleKeyDown,
1173
- placeholder,
1174
- disabled: disabled || loading,
1175
- autoFocus,
1176
- className: cn("flex-1 text-sm", inputVariantStyles[variant], inputClassName)
1177
- }
1178
- ),
1179
- rightActions,
1180
- showSendButton && /* @__PURE__ */ jsx(
1181
- Button,
1182
- {
1183
- type: "submit",
1184
- size: "sm",
1185
- variant: variant === "minimal" ? "ghost" : "outline",
1186
- disabled: !value.trim() || disabled || loading,
1187
- className: "size-8 shrink-0 p-0",
1188
- children: sendButtonContent || /* @__PURE__ */ jsx(SendIcon, { className: "size-4" })
1189
- }
1190
- )
1191
- ] })
1230
+ type,
1231
+ className: cn(
1232
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
1233
+ className
1234
+ ),
1235
+ ref,
1236
+ ...props
1192
1237
  }
1193
1238
  );
1194
1239
  }
1195
1240
  );
1196
- PromptInput.displayName = "PromptInput";
1241
+ Input.displayName = "Input";
1197
1242
  var attachmentIcons = {
1198
1243
  image: ImageIcon,
1199
1244
  audio: MicIcon,
@@ -6227,7 +6272,7 @@ function FloatingWidget({
6227
6272
  children,
6228
6273
  isLoading && /* @__PURE__ */ jsx(TypingIndicator, { size: "sm" })
6229
6274
  ] }) }),
6230
- quickReplies && /* @__PURE__ */ jsx("div", { className: "flex gap-1.5 overflow-x-auto px-4 pb-2", children: quickReplies }),
6275
+ quickReplies && /* @__PURE__ */ jsx("div", { className: "max-h-[40%] shrink-0 overflow-y-auto border-t bg-muted/30 px-4 py-2", children: quickReplies }),
6231
6276
  input,
6232
6277
  footer && /* @__PURE__ */ jsx("div", { className: "border-t px-4 py-1.5", children: /* @__PURE__ */ jsx("p", { className: "text-center text-[10px] text-muted-foreground", children: footer }) })
6233
6278
  ]