@shapesos/clay 0.14.0 → 0.15.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.
@@ -802,43 +802,148 @@ var PromptInputSubmit = ({
802
802
 
803
803
  // src/components/ai-elements/mouse-grid/mouse-grid.tsx
804
804
  var import_react5 = require("react");
805
+
806
+ // src/utils/prefers-reduced-motion.ts
807
+ function prefersReducedMotion() {
808
+ return typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-reduced-motion: reduce)").matches : false;
809
+ }
810
+
811
+ // src/components/ai-elements/mouse-grid/mouse-grid.tsx
805
812
  var import_jsx_runtime5 = require("react/jsx-runtime");
806
- function MouseGrid({ glowColor } = {}) {
813
+ function MouseGrid({ glowColor, colorCycleMs = 4e3, autoDrift = false } = {}) {
807
814
  const layerRef = (0, import_react5.useRef)(null);
815
+ const glowRef = (0, import_react5.useRef)(null);
808
816
  (0, import_react5.useEffect)(() => {
817
+ const driftEnabled = autoDrift && !prefersReducedMotion();
809
818
  let raf = 0;
819
+ let driftRaf = 0;
820
+ let lastDriftTime = 0;
810
821
  let clientX = 0;
811
822
  let clientY = 0;
823
+ let pointerInside = false;
824
+ let centerX = 0;
825
+ let centerY = 0;
826
+ let hasCenter = false;
827
+ function setCenter(x, y) {
828
+ const layer = layerRef.current;
829
+ if (!layer) {
830
+ return;
831
+ }
832
+ centerX = x;
833
+ centerY = y;
834
+ hasCenter = true;
835
+ layer.style.setProperty("--vibe-mx", `${x}px`);
836
+ layer.style.setProperty("--vibe-my", `${y}px`);
837
+ }
812
838
  function flush() {
813
839
  raf = 0;
814
840
  const layer = layerRef.current;
815
841
  if (!layer) {
816
842
  return;
817
843
  }
844
+ if (driftEnabled && !pointerInside) {
845
+ return;
846
+ }
818
847
  const rect = layer.getBoundingClientRect();
819
- layer.style.setProperty("--vibe-mx", `${clientX - rect.left}px`);
820
- layer.style.setProperty("--vibe-my", `${clientY - rect.top}px`);
848
+ setCenter(clientX - rect.left, clientY - rect.top);
821
849
  }
822
850
  function onMove(event) {
823
851
  clientX = event.clientX;
824
852
  clientY = event.clientY;
853
+ const layer = layerRef.current;
854
+ if (layer) {
855
+ const rect = layer.getBoundingClientRect();
856
+ pointerInside = clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
857
+ }
858
+ if (pointerInside) {
859
+ stopDrift();
860
+ } else {
861
+ startDrift();
862
+ }
825
863
  if (raf) {
826
864
  return;
827
865
  }
828
866
  raf = requestAnimationFrame(flush);
829
867
  }
868
+ function onPointerLeave() {
869
+ pointerInside = false;
870
+ startDrift();
871
+ }
872
+ function drift(time) {
873
+ const delta = lastDriftTime ? time - lastDriftTime : 16.67;
874
+ lastDriftTime = time;
875
+ driftRaf = requestAnimationFrame(drift);
876
+ const layer = layerRef.current;
877
+ if (!layer) {
878
+ return;
879
+ }
880
+ const { width, height } = layer.getBoundingClientRect();
881
+ if (!hasCenter) {
882
+ centerX = width / 2;
883
+ centerY = height / 2;
884
+ }
885
+ const targetX = width * (0.5 + 0.32 * Math.sin(time * 37e-5) + 0.12 * Math.sin(time * 91e-5));
886
+ const targetY = height * (0.5 + 0.32 * Math.cos(time * 41e-5) + 0.12 * Math.sin(time * 11e-4));
887
+ const alpha = 1 - Math.exp(-25e-4 * delta);
888
+ setCenter(centerX + (targetX - centerX) * alpha, centerY + (targetY - centerY) * alpha);
889
+ }
890
+ function startDrift() {
891
+ if (!driftEnabled || driftRaf) {
892
+ return;
893
+ }
894
+ lastDriftTime = 0;
895
+ driftRaf = requestAnimationFrame(drift);
896
+ }
897
+ function stopDrift() {
898
+ if (driftRaf) {
899
+ cancelAnimationFrame(driftRaf);
900
+ driftRaf = 0;
901
+ }
902
+ }
830
903
  window.addEventListener("mousemove", onMove, { passive: true });
904
+ document.documentElement.addEventListener("mouseleave", onPointerLeave);
905
+ startDrift();
831
906
  return () => {
832
907
  window.removeEventListener("mousemove", onMove);
908
+ document.documentElement.removeEventListener("mouseleave", onPointerLeave);
833
909
  if (raf) {
834
910
  cancelAnimationFrame(raf);
835
911
  }
912
+ stopDrift();
836
913
  };
837
- }, []);
838
- const glowStyle = glowColor ? { "--vibe-glow-color": glowColor } : void 0;
914
+ }, [autoDrift]);
915
+ const colorList = Array.isArray(glowColor) ? glowColor : glowColor != null ? [glowColor] : [];
916
+ const glowColorsKey = JSON.stringify(colorList);
917
+ (0, import_react5.useEffect)(() => {
918
+ const glow = glowRef.current;
919
+ if (!glow) {
920
+ return;
921
+ }
922
+ const colors2 = JSON.parse(glowColorsKey).filter(Boolean);
923
+ const staticColor = colors2[0];
924
+ if (staticColor) {
925
+ glow.style.setProperty("--vibe-glow-color", staticColor);
926
+ }
927
+ const clearColor = () => glow.style.removeProperty("--vibe-glow-color");
928
+ if (colors2.length < 2 || prefersReducedMotion()) {
929
+ return staticColor ? clearColor : void 0;
930
+ }
931
+ let index = 0;
932
+ const raf = requestAnimationFrame(() => glow.style.setProperty("--vibe-glow-cycle", `${colorCycleMs}ms`));
933
+ const timer = setInterval(() => {
934
+ index = (index + 1) % colors2.length;
935
+ glow.style.setProperty("--vibe-glow-color", colors2[index]);
936
+ }, colorCycleMs);
937
+ return () => {
938
+ cancelAnimationFrame(raf);
939
+ clearInterval(timer);
940
+ glow.style.removeProperty("--vibe-glow-cycle");
941
+ clearColor();
942
+ };
943
+ }, [glowColorsKey, colorCycleMs]);
839
944
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: layerRef, "aria-hidden": "true", className: "vibe-mouse-grid-layer", children: [
840
945
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vibe-mouse-grid" }),
841
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vibe-mouse-glow", style: glowStyle })
946
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: glowRef, className: "vibe-mouse-glow" })
842
947
  ] });
843
948
  }
844
949
 
@@ -854,7 +959,7 @@ var Suggestion = ({ suggestion, onClick, className, children, ...props }) => {
854
959
  type: "button",
855
960
  onClick: handleClick,
856
961
  className: cn(
857
- "cursor-pointer whitespace-nowrap rounded-full border border-brown-30 bg-white px-4 py-2 text-sm text-brown-100 transition-colors hover:bg-brown-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brown-40",
962
+ "cursor-pointer whitespace-nowrap rounded-[12px] border border-brown-30 bg-white px-4 py-2 text-sm text-brown-100 transition-colors hover:bg-brown-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brown-40",
858
963
  className
859
964
  ),
860
965
  ...props,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/ai-elements/index.ts","../src/components/ai-elements/prompt-input/prompt-input.tsx","../src/lib/utils.ts","../src/components/button/button.tsx","../src/components/icon/icon.tsx","../src/components/icon/icon-styles.ts","../src/components/button/button-styles.ts","../src/tokens/colors.ts","../src/tokens/typography.ts","../src/components/button/constants.ts","../src/components/text-area/text-area.tsx","../src/utils/merge-refs.ts","../src/components/text-area/text-area-styles.ts","../src/components/ai-elements/prompt-input/types.ts","../src/components/ai-elements/mouse-grid/mouse-grid.tsx","../src/components/ai-elements/suggestion/suggestion.tsx"],"sourcesContent":["export {\n CHAT_STATUS,\n PromptInput,\n PromptInputFooter,\n PromptInputSubmit,\n PromptInputTextarea,\n PromptInputTools,\n} from \"./prompt-input\";\nexport type {\n ChatStatus,\n PromptInputFooterProps,\n PromptInputMessage,\n PromptInputProps,\n PromptInputSubmitProps,\n PromptInputTextareaProps,\n PromptInputToolsProps,\n} from \"./prompt-input\";\nexport { MouseGrid } from \"./mouse-grid\";\nexport type { MouseGridProps } from \"./mouse-grid\";\nexport { Suggestion, Suggestions } from \"./suggestion\";\nexport type { SuggestionProps, SuggestionsProps } from \"./suggestion\";\n","import { forwardRef, useCallback } from \"react\";\nimport type { FormEventHandler, KeyboardEventHandler, MouseEventHandler } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/button/button\";\nimport { BUTTON_INTENT, BUTTON_SIZE } from \"@/components/button/constants\";\nimport { TextArea } from \"@/components/text-area/text-area\";\nimport { CHAT_STATUS } from \"./types\";\nimport type {\n PromptInputFooterProps,\n PromptInputProps,\n PromptInputSubmitProps,\n PromptInputTextareaProps,\n PromptInputToolsProps,\n} from \"./types\";\n\n/* ------------------------------------------------------------------------------------------------\n * Originally vendored from `@vercel/ai-elements`'s `prompt-input` registry entry. Slimmed hard to\n * the creation-surface essentials a consumer composes into a prompt-launcher hero: `PromptInput`\n * (form wrapper), `PromptInputTextarea`, `PromptInputFooter`, `PromptInputTools`, `PromptInputSubmit`.\n *\n * Everything else from the upstream entry is intentionally dropped: the action menu\n * (`PromptInputActionMenu*`), attachment / screenshot actions, the attachments strip, the\n * provider/controller contexts, and the `Select` / `HoverCard` / `Command` / `Tab` families. That\n * also sheds the upstream `nanoid` (id-per-attachment) dependency.\n *\n * Rewiring to clay's single-sourced primitives let this primitive ship with ZERO new runtime\n * dependencies — diverging from the original shared spec, which assumed the kept set would still\n * lean on `@base-ui/react`, `ai`, and `lucide-react`:\n * - upstream `InputGroupButton` (submit) → clay `Button` (filled, `type=\"button\"`, consumer label).\n * - upstream `InputGroupTextarea` → clay `TextArea` (auto-resize, transparent chrome).\n * - `lucide-react` icons → clay's already-bundled `@tabler/icons-react`.\n * - `ai`'s `ChatStatus` → a local ready/error status (see `./types`).\n *\n * Because clay's `Button` always renders `type=\"button\"`, native form submit isn't available;\n * both the Enter-key handler and the submit button trigger `form.requestSubmit()` explicitly. And\n * because clay's `TextArea` doesn't forward a `name` attribute, `PromptInput` reads the textarea's\n * value straight off the DOM at submit time rather than via `FormData` — keeping the form wrapper\n * decoupled from whoever controls the textarea's value.\n *\n * Types live in `./types`.\n * ------------------------------------------------------------------------------------------------ */\n\n/**\n * Form wrapper for a prompt composer. Renders a bordered, rounded surface; stacks its children\n * (textarea + footer) vertically. Reads the nested textarea's value on submit and forwards it to\n * `onSubmit`. Empty / whitespace-only submissions, and all submissions while `disabled`, are\n * ignored.\n */\nexport const PromptInput = ({ className, onSubmit, disabled, children, ...props }: PromptInputProps) => {\n const handleSubmit: FormEventHandler<HTMLFormElement> = useCallback(\n (event) => {\n event.preventDefault();\n if (disabled) {\n return;\n }\n const textarea = event.currentTarget.querySelector(\"textarea\");\n const text = textarea?.value ?? \"\";\n if (!text.trim()) {\n return;\n }\n onSubmit({ text }, event);\n },\n [disabled, onSubmit]\n );\n\n return (\n <form\n className={cn(\n \"flex w-full flex-col overflow-hidden rounded-xl border bg-background shadow-lg shadow-foreground/5\",\n className\n )}\n onSubmit={handleSubmit}\n {...props}\n >\n {children}\n </form>\n );\n};\n\n/**\n * Auto-resizing textarea for the prompt composer. Wraps clay's `TextArea` and adds Enter-to-submit\n * (Shift+Enter inserts a newline; submission is suppressed while an IME composition is active). The\n * consumer's `onKeyDown` runs first and can `preventDefault()` to opt out of the built-in Enter\n * handling.\n *\n * Horizontal padding lives on the textarea itself (not the wrapper) so its overflow scrollbar sits\n * flush against the wrapper's right edge; the wrapper only owns the vertical padding.\n */\nexport const PromptInputTextarea = forwardRef<HTMLTextAreaElement, PromptInputTextareaProps>(\n function PromptInputTextarea({ className, onKeyDown, placeholder = \"What would you like to know?\", ...props }, ref) {\n const handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = useCallback(\n (event) => {\n onKeyDown?.(event);\n if (event.defaultPrevented) {\n return;\n }\n if (event.key === \"Enter\" && !event.shiftKey && !event.nativeEvent.isComposing) {\n event.preventDefault();\n event.currentTarget.form?.requestSubmit();\n }\n },\n [onKeyDown]\n );\n\n return (\n <div className={cn(\"py-3\", className)}>\n <TextArea ref={ref} className=\"px-4\" onKeyDown={handleKeyDown} placeholder={placeholder} {...props} />\n </div>\n );\n }\n);\n\n/**\n * Footer row beneath the textarea — left tools and the right-aligned submit button. Horizontal\n * padding matches {@link PromptInputTextarea}'s (`px-4`) so the tools/submit align with the\n * textarea's text edges.\n */\nexport const PromptInputFooter = ({ className, ...props }: PromptInputFooterProps) => (\n <div className={cn(\"flex items-center justify-between gap-1 px-4 pb-3\", className)} {...props} />\n);\n\n/** Left-aligned cluster inside {@link PromptInputFooter} (e.g. the submit hint). */\nexport const PromptInputTools = ({ className, ...props }: PromptInputToolsProps) => (\n <div className={cn(\"flex min-w-0 items-center gap-1\", className)} {...props} />\n);\n\n/**\n * Submit button for the prompt composer — a filled clay `Button` whose text is the consumer's\n * `label` (pass a localized string for i18n). Always submits the form via `form.requestSubmit()` on\n * click (clay buttons render `type=\"button\"`); the consumer disables it while a generation is in\n * flight. `status` drives the color: `error` renders the error (red) intent, otherwise primary.\n */\nexport const PromptInputSubmit = ({\n label = \"Submit\",\n status = CHAT_STATUS.READY,\n disabled,\n className,\n}: PromptInputSubmitProps) => {\n const handleClick = useCallback<MouseEventHandler<HTMLButtonElement>>((event) => {\n event.currentTarget.form?.requestSubmit();\n }, []);\n\n return (\n <Button\n intent={status === CHAT_STATUS.ERROR ? BUTTON_INTENT.ERROR : BUTTON_INTENT.PRIMARY}\n size={BUTTON_SIZE.XS}\n className={className}\n disabled={disabled}\n onClick={handleClick}\n >\n {label}\n </Button>\n );\n};\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Combines class names using clsx and tailwind-merge — the standard shadcn/ui helper.\n * Tailwind classes that conflict (e.g. `p-2 p-4`) get merged so the last one wins.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { forwardRef } from \"react\";\nimport { Icon } from \"../icon/icon\";\nimport { StyledButton } from \"./button-styles\";\nimport { BUTTON_INTENT, BUTTON_SIZE, BUTTON_VARIANT, ICON_POSITION } from \"./constants\";\nimport type { ButtonProps } from \"./types\";\n\n/** A versatile button component with multiple variants and sizes. */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(\n {\n children,\n variant = BUTTON_VARIANT.SOLID,\n intent = BUTTON_INTENT.PRIMARY,\n size = BUTTON_SIZE.M,\n icon,\n iconPosition = ICON_POSITION.LEADING,\n disabled = false,\n onClick,\n className,\n \"aria-label\": ariaLabel,\n },\n ref\n) {\n const iconElement = icon ? <Icon icon={icon} size={16} /> : null;\n\n return (\n <StyledButton\n ref={ref}\n type=\"button\"\n $variant={variant}\n $intent={intent}\n $size={size}\n disabled={disabled}\n onClick={disabled ? undefined : onClick}\n className={className}\n aria-label={ariaLabel}\n >\n {iconPosition === ICON_POSITION.LEADING && iconElement}\n <span>{children}</span>\n {iconPosition === ICON_POSITION.TRAILING && iconElement}\n </StyledButton>\n );\n});\n","import { forwardRef } from \"react\";\n\nimport { IconWrapper, getStrokeWidth } from \"./icon-styles\";\nimport type { IconProps } from \"./types\";\n\nconst DEFAULT_SIZE = 16;\n\nexport const Icon = forwardRef<HTMLSpanElement, IconProps>(function Icon(\n { icon: IconComponent, size = DEFAULT_SIZE, color, className, \"aria-label\": ariaLabel },\n ref\n) {\n return (\n <IconWrapper\n ref={ref}\n className={className}\n $color={color}\n aria-label={ariaLabel}\n role={ariaLabel ? \"img\" : undefined}\n >\n <IconComponent width={size} height={size} strokeWidth={getStrokeWidth(size)} />\n </IconWrapper>\n );\n});\n","import styled from \"styled-components\";\n\nexport const STROKE_WIDTH_BY_SIZE: Record<number, number> = {\n 12: 1.4,\n 14: 1.4,\n 16: 1.8,\n 18: 1.8,\n 20: 1.8,\n 24: 1.8,\n};\n\nexport const DEFAULT_STROKE_WIDTH = 1.8;\n\nexport function getStrokeWidth(size: number): number {\n return STROKE_WIDTH_BY_SIZE[size] ?? DEFAULT_STROKE_WIDTH;\n}\n\nexport const IconWrapper = styled.span<{ $color?: string }>`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: ${({ $color }) => $color ?? \"currentColor\"};\n flex-shrink: 0;\n`;\n","import styled, { css } from \"styled-components\";\nimport { colors } from \"../../tokens/colors\";\nimport { typographyMixin, typographyTypes } from \"../../tokens/typography\";\nimport { BUTTON_INTENT, BUTTON_SIZE, BUTTON_VARIANT } from \"./constants\";\nimport type { ButtonIntent, ButtonSize, ButtonVariant } from \"./types\";\n\ninterface IntentColors {\n /** Primary fill / text color. */\n base: string;\n /** Hover fill for solid variant. */\n hover: string;\n /** Muted fill for disabled solid variant. */\n disabledBg: string;\n /** Muted text for disabled state. */\n disabledText: string;\n /** Subtle hover background for outline/ghost variants. */\n subtleHover: string;\n /** Border color for outline variant. */\n border: string;\n /** Muted border for disabled outline variant. */\n disabledBorder: string;\n}\n\nconst intentColors: Record<ButtonIntent, IntentColors> = {\n [BUTTON_INTENT.PRIMARY]: {\n base: colors[\"brown-100\"],\n hover: colors[\"brown-90\"],\n disabledBg: colors[\"brown-20\"],\n disabledText: colors[\"brown-50\"],\n subtleHover: colors[\"brown-20\"],\n border: colors[\"brown-40\"],\n disabledBorder: colors[\"brown-20\"],\n },\n [BUTTON_INTENT.ERROR]: {\n base: colors[\"red-500\"],\n hover: colors[\"red-600\"],\n disabledBg: colors[\"red-100\"],\n disabledText: colors[\"red-200\"],\n subtleHover: colors[\"red-50\"],\n border: colors[\"red-200\"],\n disabledBorder: colors[\"red-100\"],\n },\n};\n\ninterface SizeValues {\n padding: string;\n borderRadius: string;\n gap: string;\n}\n\nconst sizeValues: Record<ButtonSize, SizeValues> = {\n [BUTTON_SIZE.XS]: { padding: \"6px 10px\", borderRadius: \"8px\", gap: \"4px\" },\n [BUTTON_SIZE.S]: { padding: \"8px 12px\", borderRadius: \"10px\", gap: \"6px\" },\n [BUTTON_SIZE.M]: { padding: \"10px 14px\", borderRadius: \"10px\", gap: \"6px\" },\n};\n\nfunction sizeMixin({ $size }: { $size: ButtonSize }): ReturnType<typeof css> {\n const s = sizeValues[$size];\n return css`\n padding: ${s.padding};\n border-radius: ${s.borderRadius};\n gap: ${s.gap};\n `;\n}\n\ninterface VariantColorMap {\n background: string;\n color: string;\n border: string;\n hoverBg: string;\n disabledBg?: string;\n disabledColor: string;\n disabledBorder?: string;\n}\n\nconst variantColorMap: Record<ButtonVariant, (c: IntentColors) => VariantColorMap> = {\n [BUTTON_VARIANT.SOLID]: (c) => ({\n background: c.base,\n color: colors.white,\n border: \"none\",\n hoverBg: c.hover,\n disabledBg: c.disabledBg,\n disabledColor: c.disabledText,\n }),\n [BUTTON_VARIANT.OUTLINE]: (c) => ({\n background: colors.white,\n color: c.base,\n border: `1px solid ${c.border}`,\n hoverBg: c.subtleHover,\n disabledColor: c.disabledText,\n disabledBorder: c.disabledBorder,\n }),\n [BUTTON_VARIANT.GHOST]: (c) => ({\n background: \"transparent\",\n color: c.base,\n border: \"none\",\n hoverBg: c.subtleHover,\n disabledColor: c.disabledText,\n }),\n};\n\nfunction variantMixin({\n $variant,\n $intent,\n}: {\n $variant: ButtonVariant;\n $intent: ButtonIntent;\n}): ReturnType<typeof css> {\n const v = variantColorMap[$variant](intentColors[$intent]);\n\n return css`\n background: ${v.background};\n color: ${v.color};\n border: ${v.border};\n\n &:hover:not(:disabled) {\n background: ${v.hoverBg};\n }\n\n &:disabled {\n color: ${v.disabledColor};\n ${v.disabledBg ? `background: ${v.disabledBg};` : \"\"}\n ${v.disabledBorder ? `border-color: ${v.disabledBorder};` : \"\"}\n }\n `;\n}\n\n/** Styled button element with variant, intent, and size transient props. */\nexport const StyledButton = styled.button<{\n $variant: ButtonVariant;\n $intent: ButtonIntent;\n $size: ButtonSize;\n}>`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n ${typographyMixin(typographyTypes.GEIST_BODY_XS_MEDIUM)};\n transition: background-color 150ms ease, border-color 150ms ease, color 150ms ease;\n\n &:disabled {\n cursor: not-allowed;\n }\n\n ${sizeMixin}\n ${variantMixin}\n`;\n","export const colors = {\n // White\n white: \"#FFFFFF\",\n \"white-alpha-85\": \"rgba(255, 255, 255, 0.85)\",\n \"white-alpha-40\": \"rgba(255, 255, 255, 0.40)\",\n\n // Brown\n \"brown-10\": \"#FAF9F8\",\n \"brown-20\": \"#F5F3F0\",\n \"brown-30\": \"#EEEBE5\",\n \"brown-40\": \"#E6E2DA\",\n \"brown-50\": \"#CFCBC4\",\n \"brown-60\": \"#A19E99\",\n \"brown-70\": \"#73716D\",\n \"brown-80\": \"#5C5A57\",\n \"brown-90\": \"#2E2D2C\",\n \"brown-100\": \"#171716\",\n \"brown-alpha-12\": \"rgba(23, 23, 22, 0.12)\",\n \"brown-alpha-20\": \"rgba(23, 23, 22, 0.20)\",\n \"brown-alpha-55\": \"rgba(23, 23, 22, 0.55)\",\n \"brown-alpha-70\": \"rgba(23, 23, 22, 0.70)\",\n \"brown-alpha-80\": \"rgba(23, 23, 22, 0.80)\",\n \"brown-alpha-90\": \"rgba(23, 23, 22, 0.90)\",\n\n // Fuchsia\n \"fuchsia-50\": \"#FAF5FF\",\n \"fuchsia-300\": \"#F0ABFC\",\n \"fuchsia-500\": \"#D946EF\",\n \"fuchsia-600\": \"#C026D3\",\n \"fuchsia-800\": \"#86198F\",\n\n // Pink\n \"pink-50\": \"#FDF2F8\",\n \"pink-400\": \"#F472B6\",\n \"pink-600\": \"#DB2777\",\n \"pink-800\": \"#9D174D\",\n\n // Violet\n \"violet-50\": \"#F5F3FF\",\n \"violet-400\": \"#A78BFA\",\n \"violet-600\": \"#7C3AED\",\n \"violet-800\": \"#5B21B6\",\n\n // Indigo\n \"indigo-50\": \"#EEF2FF\",\n \"indigo-400\": \"#818CF8\",\n \"indigo-500\": \"#6366F1\",\n \"indigo-600\": \"#4F46E5\",\n \"indigo-800\": \"#3730A3\",\n\n // Cyan\n \"cyan-50\": \"#E7FEFF\",\n \"cyan-300\": \"#67E8F9\",\n \"cyan-600\": \"#0891B2\",\n \"cyan-900\": \"#164E63\",\n\n // Teal\n \"teal-50\": \"#EBFDF9\",\n \"teal-300\": \"#5EEAD4\",\n \"teal-600\": \"#0D9488\",\n\n // Rose\n \"rose-400\": \"#FB7185\",\n\n // Purple\n \"purple-400\": \"#C084FC\",\n\n // Blue\n \"blue-50\": \"#EFF6FF\",\n \"blue-100\": \"#DBEAFE\",\n \"blue-300\": \"#93C5FD\",\n \"blue-400\": \"#60A5FA\",\n \"blue-600\": \"#2563EB\",\n \"blue-800\": \"#1E40AF\",\n\n // Sky\n \"sky-300\": \"#7DD3FC\",\n\n // Green\n \"green-50\": \"#ECF9F0\",\n \"green-100\": \"#D4F1D9\",\n \"green-400\": \"#3DC269\",\n \"green-700\": \"#277C43\",\n \"green-800\": \"#1C5930\",\n\n // Orange\n \"orange-50\": \"#FFF7ED\",\n \"orange-100\": \"#FFEDD5\",\n \"orange-200\": \"#FED7AA\",\n \"orange-500\": \"#F97316\",\n \"orange-600\": \"#EA580C\",\n\n // Red\n \"red-50\": \"#FEF2F2\",\n \"red-100\": \"#FEE2E2\",\n \"red-200\": \"#FECACA\",\n \"red-400\": \"#F7776C\",\n \"red-500\": \"#EF4444\",\n \"red-600\": \"#DC2626\",\n} as const;\n\nexport type ColorToken = keyof typeof colors;\n","/** Available font families in the Shapes.co design system. */\nexport const fontFamilies = {\n /** Geist — primary UI font for body text, labels, headings, and display. */\n GEIST: \"Geist\",\n /** Crimson Pro — editorial/serif font, mostly italic. Used for decorative headings and pull quotes. */\n CRIMSON_PRO: \"Crimson Pro\",\n} as const;\n\n/*\n * Type-name convention: `<FAMILY>_<ROLE>_<SIZE>_<WEIGHT>[_ITALIC]`. An italic style is marked by a\n * trailing `_ITALIC` suffix on the name (mirroring io-client's `styled-mixins/typography-mixin`);\n * names without it are upright. The suffix is the single source of truth in the NAME — the matching\n * `typographyStyles` entry still carries `fontStyle: \"italic\"`.\n */\n\nexport const typographyTypes = {\n // Geist Label Caption (12px)\n GEIST_LABEL_CAPTION_REGULAR: \"GEIST_LABEL_CAPTION_REGULAR\",\n GEIST_LABEL_CAPTION_MEDIUM: \"GEIST_LABEL_CAPTION_MEDIUM\",\n GEIST_LABEL_CAPTION_SEMI_BOLD: \"GEIST_LABEL_CAPTION_SEMI_BOLD\",\n\n // Geist Body Extra Small (14px)\n GEIST_BODY_XS_REGULAR: \"GEIST_BODY_XS_REGULAR\",\n GEIST_BODY_XS_MEDIUM: \"GEIST_BODY_XS_MEDIUM\",\n GEIST_BODY_XS_BOLD: \"GEIST_BODY_XS_BOLD\",\n\n // Geist Body Small (16px)\n GEIST_BODY_S_REGULAR: \"GEIST_BODY_S_REGULAR\",\n GEIST_BODY_S_MEDIUM: \"GEIST_BODY_S_MEDIUM\",\n GEIST_BODY_S_SEMI_BOLD: \"GEIST_BODY_S_SEMI_BOLD\",\n GEIST_BODY_S_BOLD: \"GEIST_BODY_S_BOLD\",\n\n // Geist Body Medium (18px)\n GEIST_BODY_M_LIGHT: \"GEIST_BODY_M_LIGHT\",\n GEIST_BODY_M_REGULAR: \"GEIST_BODY_M_REGULAR\",\n GEIST_BODY_M_MEDIUM: \"GEIST_BODY_M_MEDIUM\",\n GEIST_BODY_M_SEMI_BOLD: \"GEIST_BODY_M_SEMI_BOLD\",\n\n // Geist Body Large (20px)\n GEIST_BODY_L_REGULAR: \"GEIST_BODY_L_REGULAR\",\n GEIST_BODY_L_MEDIUM: \"GEIST_BODY_L_MEDIUM\",\n GEIST_BODY_L_SEMI_BOLD: \"GEIST_BODY_L_SEMI_BOLD\",\n GEIST_BODY_L_BOLD: \"GEIST_BODY_L_BOLD\",\n\n // Geist Heading Small (24px)\n GEIST_HEADING_S_REGULAR: \"GEIST_HEADING_S_REGULAR\",\n GEIST_HEADING_S_MEDIUM: \"GEIST_HEADING_S_MEDIUM\",\n GEIST_HEADING_S_BOLD: \"GEIST_HEADING_S_BOLD\",\n\n // Geist Heading Medium (28px)\n GEIST_HEADING_M_BOLD: \"GEIST_HEADING_M_BOLD\",\n\n // Geist Heading Large (32px)\n GEIST_HEADING_L_REGULAR: \"GEIST_HEADING_L_REGULAR\",\n GEIST_HEADING_L_MEDIUM: \"GEIST_HEADING_L_MEDIUM\",\n GEIST_HEADING_L_SEMI_BOLD: \"GEIST_HEADING_L_SEMI_BOLD\",\n GEIST_HEADING_L_BOLD: \"GEIST_HEADING_L_BOLD\",\n\n // Geist Display Large (36px)\n GEIST_DISPLAY_L_MEDIUM: \"GEIST_DISPLAY_L_MEDIUM\",\n\n // Crimson Pro Body Small (16px, italic)\n CRIMSON_PRO_BODY_S_LIGHT_ITALIC: \"CRIMSON_PRO_BODY_S_LIGHT_ITALIC\",\n\n // Crimson Pro Body Medium (18px, italic)\n CRIMSON_PRO_BODY_M_LIGHT_ITALIC: \"CRIMSON_PRO_BODY_M_LIGHT_ITALIC\",\n\n // Crimson Pro Heading Medium (24px, italic)\n CRIMSON_PRO_HEADING_M_MEDIUM_ITALIC: \"CRIMSON_PRO_HEADING_M_MEDIUM_ITALIC\",\n\n // Crimson Pro Display Large (40px, upright)\n CRIMSON_PRO_DISPLAY_L_REGULAR: \"CRIMSON_PRO_DISPLAY_L_REGULAR\",\n\n // Crimson Pro Display Extra Large (46px, italic)\n CRIMSON_PRO_DISPLAY_XL_REGULAR_ITALIC: \"CRIMSON_PRO_DISPLAY_XL_REGULAR_ITALIC\",\n} as const;\n\n/** Union of all typography type string constants. Used as keys into `typographyStyles`. */\nexport type TypographyType = (typeof typographyTypes)[keyof typeof typographyTypes];\n\n/** CSS properties for a single typography type. All numeric values are in pixels. */\nexport interface TypographyStyle {\n /** Font family name (e.g., \"Geist\"). */\n fontFamily: string;\n /** Font size in pixels. */\n fontSize: number;\n /** Font weight (100–900). */\n fontWeight: number;\n /** Line height in pixels. */\n lineHeight: number;\n /** Letter spacing in pixels. Omitted when the font's default spacing is correct. */\n letterSpacing?: number;\n /** CSS font-style value (e.g., \"italic\"). Omitted for normal style. */\n fontStyle?: string;\n}\n\nexport const typographyStyles: Record<TypographyType, TypographyStyle> = {\n // Geist Label Caption (12px)\n [typographyTypes.GEIST_LABEL_CAPTION_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 12,\n fontWeight: 400,\n lineHeight: 16,\n },\n [typographyTypes.GEIST_LABEL_CAPTION_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 12,\n fontWeight: 500,\n lineHeight: 16,\n },\n [typographyTypes.GEIST_LABEL_CAPTION_SEMI_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 12,\n fontWeight: 600,\n lineHeight: 16,\n },\n\n // Geist Body Extra Small (14px)\n [typographyTypes.GEIST_BODY_XS_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 14,\n fontWeight: 400,\n lineHeight: 20,\n },\n [typographyTypes.GEIST_BODY_XS_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 14,\n fontWeight: 500,\n lineHeight: 20,\n },\n [typographyTypes.GEIST_BODY_XS_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 14,\n fontWeight: 600,\n lineHeight: 20,\n },\n\n // Geist Body Small (16px)\n [typographyTypes.GEIST_BODY_S_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 16,\n fontWeight: 400,\n lineHeight: 24,\n letterSpacing: -0.08,\n },\n [typographyTypes.GEIST_BODY_S_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 16,\n fontWeight: 500,\n lineHeight: 24,\n letterSpacing: -0.08,\n },\n [typographyTypes.GEIST_BODY_S_SEMI_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 16,\n fontWeight: 600,\n lineHeight: 24,\n letterSpacing: -0.08,\n },\n [typographyTypes.GEIST_BODY_S_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 16,\n fontWeight: 700,\n lineHeight: 24,\n letterSpacing: -0.08,\n },\n\n // Geist Body Medium (18px)\n [typographyTypes.GEIST_BODY_M_LIGHT]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 18,\n fontWeight: 300,\n lineHeight: 28,\n letterSpacing: -0.09,\n },\n [typographyTypes.GEIST_BODY_M_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 18,\n fontWeight: 400,\n lineHeight: 28,\n letterSpacing: -0.09,\n },\n [typographyTypes.GEIST_BODY_M_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 18,\n fontWeight: 500,\n lineHeight: 28,\n letterSpacing: -0.09,\n },\n [typographyTypes.GEIST_BODY_M_SEMI_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 18,\n fontWeight: 600,\n lineHeight: 28,\n letterSpacing: -0.09,\n },\n\n // Geist Body Large (20px)\n [typographyTypes.GEIST_BODY_L_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 20,\n fontWeight: 400,\n lineHeight: 30,\n letterSpacing: -0.2,\n },\n [typographyTypes.GEIST_BODY_L_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 20,\n fontWeight: 500,\n lineHeight: 30,\n letterSpacing: -0.2,\n },\n [typographyTypes.GEIST_BODY_L_SEMI_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 20,\n fontWeight: 600,\n lineHeight: 30,\n letterSpacing: -0.2,\n },\n [typographyTypes.GEIST_BODY_L_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 20,\n fontWeight: 700,\n lineHeight: 30,\n letterSpacing: -0.2,\n },\n\n // Geist Heading Small (24px)\n [typographyTypes.GEIST_HEADING_S_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 24,\n fontWeight: 400,\n lineHeight: 32,\n letterSpacing: -0.48,\n },\n [typographyTypes.GEIST_HEADING_S_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 24,\n fontWeight: 500,\n lineHeight: 32,\n letterSpacing: -0.48,\n },\n [typographyTypes.GEIST_HEADING_S_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 24,\n fontWeight: 700,\n lineHeight: 32,\n letterSpacing: -0.48,\n },\n\n // Geist Heading Medium (28px)\n [typographyTypes.GEIST_HEADING_M_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 28,\n fontWeight: 700,\n lineHeight: 36,\n letterSpacing: -0.6,\n },\n\n // Geist Heading Large (32px)\n [typographyTypes.GEIST_HEADING_L_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 32,\n fontWeight: 400,\n lineHeight: 40,\n letterSpacing: -0.64,\n },\n [typographyTypes.GEIST_HEADING_L_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 32,\n fontWeight: 500,\n lineHeight: 40,\n letterSpacing: -0.64,\n },\n [typographyTypes.GEIST_HEADING_L_SEMI_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 32,\n fontWeight: 600,\n lineHeight: 40,\n letterSpacing: -0.64,\n },\n [typographyTypes.GEIST_HEADING_L_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 32,\n fontWeight: 700,\n lineHeight: 40,\n letterSpacing: -0.64,\n },\n\n // Geist Display Large (36px)\n [typographyTypes.GEIST_DISPLAY_L_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 36,\n fontWeight: 500,\n lineHeight: 44,\n letterSpacing: -0.72,\n },\n\n // Crimson Pro Body Small (16px, italic)\n [typographyTypes.CRIMSON_PRO_BODY_S_LIGHT_ITALIC]: {\n fontFamily: fontFamilies.CRIMSON_PRO,\n fontSize: 16,\n fontWeight: 300,\n lineHeight: 20,\n letterSpacing: -0.32,\n fontStyle: \"italic\",\n },\n\n // Crimson Pro Body Medium (18px, italic)\n [typographyTypes.CRIMSON_PRO_BODY_M_LIGHT_ITALIC]: {\n fontFamily: fontFamilies.CRIMSON_PRO,\n fontSize: 18,\n fontWeight: 300,\n lineHeight: 28,\n letterSpacing: 0,\n fontStyle: \"italic\",\n },\n\n // Crimson Pro Heading Medium (24px, italic)\n [typographyTypes.CRIMSON_PRO_HEADING_M_MEDIUM_ITALIC]: {\n fontFamily: fontFamilies.CRIMSON_PRO,\n fontSize: 24,\n fontWeight: 400,\n lineHeight: 32,\n letterSpacing: -0.48,\n fontStyle: \"italic\",\n },\n\n // Crimson Pro Display Large (40px, upright)\n [typographyTypes.CRIMSON_PRO_DISPLAY_L_REGULAR]: {\n fontFamily: fontFamilies.CRIMSON_PRO,\n fontSize: 40,\n fontWeight: 300,\n lineHeight: 48,\n letterSpacing: -1.6,\n },\n\n // Crimson Pro Display Extra Large (46px, italic)\n [typographyTypes.CRIMSON_PRO_DISPLAY_XL_REGULAR_ITALIC]: {\n fontFamily: fontFamilies.CRIMSON_PRO,\n fontSize: 46,\n fontWeight: 400,\n lineHeight: 54,\n letterSpacing: -1.38,\n fontStyle: \"italic\",\n },\n};\n\n/**\n * Generates a CSS string for a given typography type, suitable for use in styled-components template literals.\n * @param type - The typography type constant (e.g., `typographyTypes.GEIST_BODY_S_REGULAR`).\n * @returns A semicolon-separated CSS string with font-family, font-size, font-weight, line-height, letter-spacing, and font-style.\n */\nexport function typographyMixin(type: TypographyType): string {\n const style = typographyStyles[type];\n return [\n `font-family: \"${style.fontFamily}\", sans-serif`,\n `font-size: ${style.fontSize}px`,\n `font-weight: ${style.fontWeight}`,\n `line-height: ${style.lineHeight}px`,\n `letter-spacing: ${style.letterSpacing != null ? `${style.letterSpacing}px` : \"inherit\"}`,\n `font-style: ${style.fontStyle ?? \"normal\"}`,\n ].join(\";\\n \");\n}\n","/** Available visual style variants for the Button component. */\nexport const BUTTON_VARIANT = {\n SOLID: \"solid\",\n OUTLINE: \"outline\",\n GHOST: \"ghost\",\n} as const;\n\n/** Available size presets for the Button component. */\nexport const BUTTON_SIZE = {\n XS: \"xs\",\n S: \"s\",\n M: \"m\",\n} as const;\n\n/** Available semantic intents for the Button component. */\nexport const BUTTON_INTENT = {\n PRIMARY: \"primary\",\n ERROR: \"error\",\n} as const;\n\n/** Available icon positions relative to the label text. */\nexport const ICON_POSITION = {\n LEADING: \"leading\",\n TRAILING: \"trailing\",\n} as const;\n","import { forwardRef, useCallback, useLayoutEffect, useRef, type ChangeEvent } from \"react\";\n\nimport { mergeRefs } from \"@/utils/merge-refs\";\nimport { StyledTextArea } from \"./text-area-styles\";\nimport type { TextAreaProps } from \"./types\";\n\nexport const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(function TextArea(\n { value, onChange, placeholder, maxHeight, rows = 1, autoFocus, onKeyDown, disabled, className },\n externalRef\n) {\n const internalRef = useRef<HTMLTextAreaElement>(null);\n\n // Auto-resize: recalculates height whenever value changes so the textarea\n // grows/shrinks to fit its content (also restores correct height when the\n // component re-mounts or becomes visible again after being hidden).\n useLayoutEffect(() => {\n const el = internalRef.current;\n if (el) {\n el.style.height = \"auto\";\n el.style.height = `${el.scrollHeight}px`;\n }\n }, [value]);\n\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLTextAreaElement>) => {\n onChange(e.target.value);\n },\n [onChange]\n );\n\n return (\n <StyledTextArea\n ref={mergeRefs(internalRef, externalRef)}\n value={value}\n onChange={handleChange}\n placeholder={placeholder}\n $maxHeight={maxHeight}\n rows={rows}\n autoFocus={autoFocus}\n onKeyDown={onKeyDown}\n disabled={disabled}\n className={className}\n />\n );\n});\n","import type { Ref } from \"react\";\n\n/**\n * Combines multiple React refs into a single callback ref.\n * Useful when a component needs to forward its ref while also keeping a local ref.\n *\n * @param refs - Any number of React refs (callback refs, RefObjects, or `undefined`).\n * @returns A callback ref that updates all provided refs when the DOM node changes.\n */\nexport function mergeRefs<T>(...refs: (Ref<T> | undefined)[]): (node: T | null) => void {\n return (node) => {\n for (const ref of refs) {\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<T | null>).current = node;\n }\n }\n };\n}\n","import styled from \"styled-components\";\n\nimport { colors } from \"../../tokens/colors\";\nimport { typographyMixin, typographyTypes } from \"../../tokens/typography\";\n\nexport const StyledTextArea = styled.textarea<{ $maxHeight?: number }>`\n ${typographyMixin(typographyTypes.GEIST_BODY_S_REGULAR)};\n color: ${colors[\"brown-100\"]};\n border: none;\n outline: none;\n resize: none;\n width: 100%;\n background: transparent;\n vertical-align: bottom;\n max-height: ${({ $maxHeight }) => ($maxHeight ? `${$maxHeight}px` : \"none\")};\n overflow-y: ${({ $maxHeight }) => ($maxHeight ? \"auto\" : \"hidden\")};\n\n &::placeholder {\n color: ${colors[\"brown-50\"]};\n }\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n`;\n","import type { FormEvent, HTMLAttributes } from \"react\";\n\nimport type { TextAreaProps } from \"@/components/text-area/types\";\n\n/**\n * Submission status the submit button reflects. The composer has no cancellation and no\n * intermediate \"generating\" state of its own — the consumer disables the button while busy — so\n * only the idle and error states are modeled here.\n */\nexport const CHAT_STATUS = {\n /** Idle / ready to submit. */\n READY: \"ready\",\n /** The last submission errored — the button shows a retry affordance. */\n ERROR: \"error\",\n} as const;\n\n/** Submission status the submit button reflects. */\nexport type ChatStatus = (typeof CHAT_STATUS)[keyof typeof CHAT_STATUS];\n\n/** Payload emitted by {@link PromptInput} on submit. v1 carries only text (attachments are cut). */\nexport interface PromptInputMessage {\n /** The current textarea value at submit time. */\n text: string;\n}\n\n/** Props for the {@link PromptInput} form wrapper. */\nexport type PromptInputProps = Omit<HTMLAttributes<HTMLFormElement>, \"onSubmit\"> & {\n /**\n * Fired when the form is submitted (Enter key or the submit button) with non-empty text.\n * Receives the captured message and the underlying form event.\n */\n onSubmit: (message: PromptInputMessage, event: FormEvent<HTMLFormElement>) => void;\n /**\n * Blocks submission across every trigger (Enter key, submit button, programmatic) when `true` —\n * e.g. while a generation is in flight. The single gate that keeps the Enter path in sync with a\n * disabled submit button. @default false\n */\n disabled?: boolean;\n};\n\n/** Props for {@link PromptInputTextarea} — clay `TextArea` props; `className` styles the wrapper. */\nexport type PromptInputTextareaProps = TextAreaProps;\n\n/** Props for {@link PromptInputFooter}. */\nexport type PromptInputFooterProps = HTMLAttributes<HTMLDivElement>;\n\n/** Props for {@link PromptInputTools}. */\nexport type PromptInputToolsProps = HTMLAttributes<HTMLDivElement>;\n\n/** Props for {@link PromptInputSubmit}. */\nexport interface PromptInputSubmitProps {\n /** Button label — pass a localized string (i18n) from the consumer. @default \"Submit\" */\n label?: string;\n /** Drives the button color: `error` renders the red error intent, otherwise primary. @default \"ready\" */\n status?: ChatStatus;\n /** Whether the button is non-interactive (e.g. empty input or a generation in flight). */\n disabled?: boolean;\n /** Additional CSS class name. */\n className?: string;\n}\n","import { useEffect, useRef, type CSSProperties } from \"react\";\n\nimport type { MouseGridProps } from \"./types\";\n\n/**\n * Absolutely-positioned grid backdrop, confined to its nearest positioned ancestor (give the\n * parent `position: relative` + `overflow: hidden` to clip it). The grid is revealed only near the\n * cursor via a radial mask whose center is driven by the `--vibe-mx` / `--vibe-my` CSS vars,\n * updated by a rAF-throttled `mousemove` listener. Renders behind all content (`z-0`) and never\n * blocks pointer events.\n *\n * Cursor coordinates are translated from viewport space (`clientX` / `clientY`) into layer-local\n * space (minus the layer's `getBoundingClientRect()` origin) and written onto the layer element\n * itself — not the document root — so the glow tracks correctly even though the layer no longer\n * fills the viewport. The rect read happens inside the rAF so it batches with paint.\n *\n * Pure `useEffect` + `requestAnimationFrame`, no animation library. The `.vibe-mouse-grid-layer` /\n * `.vibe-mouse-grid` / `.vibe-mouse-glow` styles ship in `@shapesos/clay/blocks/styles.css`.\n */\nexport function MouseGrid({ glowColor }: MouseGridProps = {}) {\n const layerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n let raf = 0;\n let clientX = 0;\n let clientY = 0;\n function flush() {\n raf = 0;\n const layer = layerRef.current;\n if (!layer) {\n return;\n }\n const rect = layer.getBoundingClientRect();\n layer.style.setProperty(\"--vibe-mx\", `${clientX - rect.left}px`);\n layer.style.setProperty(\"--vibe-my\", `${clientY - rect.top}px`);\n }\n function onMove(event: MouseEvent) {\n clientX = event.clientX;\n clientY = event.clientY;\n if (raf) {\n return;\n }\n raf = requestAnimationFrame(flush);\n }\n window.addEventListener(\"mousemove\", onMove, { passive: true });\n return () => {\n window.removeEventListener(\"mousemove\", onMove);\n if (raf) {\n cancelAnimationFrame(raf);\n }\n };\n }, []);\n\n const glowStyle = glowColor ? ({ \"--vibe-glow-color\": glowColor } as CSSProperties) : undefined;\n\n return (\n <div ref={layerRef} aria-hidden=\"true\" className=\"vibe-mouse-grid-layer\">\n <div className=\"vibe-mouse-grid\" />\n <div className=\"vibe-mouse-glow\" style={glowStyle} />\n </div>\n );\n}\n","import { useCallback } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\nimport type { SuggestionProps, SuggestionsProps } from \"./types\";\n\n/* ------------------------------------------------------------------------------------------------\n * Vendored + slimmed from `@vercel/ai-elements`'s `suggestion` registry entry. Upstream wraps the\n * pills in a shadcn `ScrollArea` and renders each as a shadcn `Button variant=\"outline\"`; clay has\n * neither, so this ships a dependency-free row (`flex flex-wrap`) of Tailwind-styled pills using\n * clay's named color tokens. Engine note: this is vendored ai-elements chrome, so it's Tailwind —\n * clay's `Button` is styled-components with fixed radii and can't produce the rounded-full pill.\n * ------------------------------------------------------------------------------------------------ */\n\n/**\n * A centered, wrapping row of {@link Suggestion} pills — e.g. starter prompts beneath a composer.\n * Compose `Suggestion` children inside.\n */\nexport const Suggestions = ({ className, ...props }: SuggestionsProps) => (\n <div className={cn(\"flex flex-wrap items-center justify-center gap-3\", className)} {...props} />\n);\n\n/**\n * A single tappable suggestion pill. Renders `children` if provided, otherwise the `suggestion`\n * text, and calls `onClick(suggestion)` when clicked.\n */\nexport const Suggestion = ({ suggestion, onClick, className, children, ...props }: SuggestionProps) => {\n const handleClick = useCallback(() => onClick?.(suggestion), [onClick, suggestion]);\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n className={cn(\n \"cursor-pointer whitespace-nowrap rounded-full border border-brown-30 bg-white px-4 py-2 text-sm text-brown-100 transition-colors hover:bg-brown-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brown-40\",\n className\n )}\n {...props}\n >\n {children ?? suggestion}\n </button>\n );\n};\n"],"mappings":"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","names":["import_react","import_react","styled","Icon","import_styled_components","styled","import_jsx_runtime","Button","import_react","import_styled_components","styled","import_jsx_runtime","TextArea","import_jsx_runtime","PromptInputTextarea","import_react","import_jsx_runtime","import_react","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/components/ai-elements/index.ts","../src/components/ai-elements/prompt-input/prompt-input.tsx","../src/lib/utils.ts","../src/components/button/button.tsx","../src/components/icon/icon.tsx","../src/components/icon/icon-styles.ts","../src/components/button/button-styles.ts","../src/tokens/colors.ts","../src/tokens/typography.ts","../src/components/button/constants.ts","../src/components/text-area/text-area.tsx","../src/utils/merge-refs.ts","../src/components/text-area/text-area-styles.ts","../src/components/ai-elements/prompt-input/types.ts","../src/components/ai-elements/mouse-grid/mouse-grid.tsx","../src/utils/prefers-reduced-motion.ts","../src/components/ai-elements/suggestion/suggestion.tsx"],"sourcesContent":["export {\n CHAT_STATUS,\n PromptInput,\n PromptInputFooter,\n PromptInputSubmit,\n PromptInputTextarea,\n PromptInputTools,\n} from \"./prompt-input\";\nexport type {\n ChatStatus,\n PromptInputFooterProps,\n PromptInputMessage,\n PromptInputProps,\n PromptInputSubmitProps,\n PromptInputTextareaProps,\n PromptInputToolsProps,\n} from \"./prompt-input\";\nexport { MouseGrid } from \"./mouse-grid\";\nexport type { MouseGridProps } from \"./mouse-grid\";\nexport { Suggestion, Suggestions } from \"./suggestion\";\nexport type { SuggestionProps, SuggestionsProps } from \"./suggestion\";\n","import { forwardRef, useCallback } from \"react\";\nimport type { FormEventHandler, KeyboardEventHandler, MouseEventHandler } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/button/button\";\nimport { BUTTON_INTENT, BUTTON_SIZE } from \"@/components/button/constants\";\nimport { TextArea } from \"@/components/text-area/text-area\";\nimport { CHAT_STATUS } from \"./types\";\nimport type {\n PromptInputFooterProps,\n PromptInputProps,\n PromptInputSubmitProps,\n PromptInputTextareaProps,\n PromptInputToolsProps,\n} from \"./types\";\n\n/* ------------------------------------------------------------------------------------------------\n * Originally vendored from `@vercel/ai-elements`'s `prompt-input` registry entry. Slimmed hard to\n * the creation-surface essentials a consumer composes into a prompt-launcher hero: `PromptInput`\n * (form wrapper), `PromptInputTextarea`, `PromptInputFooter`, `PromptInputTools`, `PromptInputSubmit`.\n *\n * Everything else from the upstream entry is intentionally dropped: the action menu\n * (`PromptInputActionMenu*`), attachment / screenshot actions, the attachments strip, the\n * provider/controller contexts, and the `Select` / `HoverCard` / `Command` / `Tab` families. That\n * also sheds the upstream `nanoid` (id-per-attachment) dependency.\n *\n * Rewiring to clay's single-sourced primitives let this primitive ship with ZERO new runtime\n * dependencies — diverging from the original shared spec, which assumed the kept set would still\n * lean on `@base-ui/react`, `ai`, and `lucide-react`:\n * - upstream `InputGroupButton` (submit) → clay `Button` (filled, `type=\"button\"`, consumer label).\n * - upstream `InputGroupTextarea` → clay `TextArea` (auto-resize, transparent chrome).\n * - `lucide-react` icons → clay's already-bundled `@tabler/icons-react`.\n * - `ai`'s `ChatStatus` → a local ready/error status (see `./types`).\n *\n * Because clay's `Button` always renders `type=\"button\"`, native form submit isn't available;\n * both the Enter-key handler and the submit button trigger `form.requestSubmit()` explicitly. And\n * because clay's `TextArea` doesn't forward a `name` attribute, `PromptInput` reads the textarea's\n * value straight off the DOM at submit time rather than via `FormData` — keeping the form wrapper\n * decoupled from whoever controls the textarea's value.\n *\n * Types live in `./types`.\n * ------------------------------------------------------------------------------------------------ */\n\n/**\n * Form wrapper for a prompt composer. Renders a bordered, rounded surface; stacks its children\n * (textarea + footer) vertically. Reads the nested textarea's value on submit and forwards it to\n * `onSubmit`. Empty / whitespace-only submissions, and all submissions while `disabled`, are\n * ignored.\n */\nexport const PromptInput = ({ className, onSubmit, disabled, children, ...props }: PromptInputProps) => {\n const handleSubmit: FormEventHandler<HTMLFormElement> = useCallback(\n (event) => {\n event.preventDefault();\n if (disabled) {\n return;\n }\n const textarea = event.currentTarget.querySelector(\"textarea\");\n const text = textarea?.value ?? \"\";\n if (!text.trim()) {\n return;\n }\n onSubmit({ text }, event);\n },\n [disabled, onSubmit]\n );\n\n return (\n <form\n className={cn(\n \"flex w-full flex-col overflow-hidden rounded-xl border bg-background shadow-lg shadow-foreground/5\",\n className\n )}\n onSubmit={handleSubmit}\n {...props}\n >\n {children}\n </form>\n );\n};\n\n/**\n * Auto-resizing textarea for the prompt composer. Wraps clay's `TextArea` and adds Enter-to-submit\n * (Shift+Enter inserts a newline; submission is suppressed while an IME composition is active). The\n * consumer's `onKeyDown` runs first and can `preventDefault()` to opt out of the built-in Enter\n * handling.\n *\n * Horizontal padding lives on the textarea itself (not the wrapper) so its overflow scrollbar sits\n * flush against the wrapper's right edge; the wrapper only owns the vertical padding.\n */\nexport const PromptInputTextarea = forwardRef<HTMLTextAreaElement, PromptInputTextareaProps>(\n function PromptInputTextarea({ className, onKeyDown, placeholder = \"What would you like to know?\", ...props }, ref) {\n const handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = useCallback(\n (event) => {\n onKeyDown?.(event);\n if (event.defaultPrevented) {\n return;\n }\n if (event.key === \"Enter\" && !event.shiftKey && !event.nativeEvent.isComposing) {\n event.preventDefault();\n event.currentTarget.form?.requestSubmit();\n }\n },\n [onKeyDown]\n );\n\n return (\n <div className={cn(\"py-3\", className)}>\n <TextArea ref={ref} className=\"px-4\" onKeyDown={handleKeyDown} placeholder={placeholder} {...props} />\n </div>\n );\n }\n);\n\n/**\n * Footer row beneath the textarea — left tools and the right-aligned submit button. Horizontal\n * padding matches {@link PromptInputTextarea}'s (`px-4`) so the tools/submit align with the\n * textarea's text edges.\n */\nexport const PromptInputFooter = ({ className, ...props }: PromptInputFooterProps) => (\n <div className={cn(\"flex items-center justify-between gap-1 px-4 pb-3\", className)} {...props} />\n);\n\n/** Left-aligned cluster inside {@link PromptInputFooter} (e.g. the submit hint). */\nexport const PromptInputTools = ({ className, ...props }: PromptInputToolsProps) => (\n <div className={cn(\"flex min-w-0 items-center gap-1\", className)} {...props} />\n);\n\n/**\n * Submit button for the prompt composer — a filled clay `Button` whose text is the consumer's\n * `label` (pass a localized string for i18n). Always submits the form via `form.requestSubmit()` on\n * click (clay buttons render `type=\"button\"`); the consumer disables it while a generation is in\n * flight. `status` drives the color: `error` renders the error (red) intent, otherwise primary.\n */\nexport const PromptInputSubmit = ({\n label = \"Submit\",\n status = CHAT_STATUS.READY,\n disabled,\n className,\n}: PromptInputSubmitProps) => {\n const handleClick = useCallback<MouseEventHandler<HTMLButtonElement>>((event) => {\n event.currentTarget.form?.requestSubmit();\n }, []);\n\n return (\n <Button\n intent={status === CHAT_STATUS.ERROR ? BUTTON_INTENT.ERROR : BUTTON_INTENT.PRIMARY}\n size={BUTTON_SIZE.XS}\n className={className}\n disabled={disabled}\n onClick={handleClick}\n >\n {label}\n </Button>\n );\n};\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Combines class names using clsx and tailwind-merge — the standard shadcn/ui helper.\n * Tailwind classes that conflict (e.g. `p-2 p-4`) get merged so the last one wins.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { forwardRef } from \"react\";\nimport { Icon } from \"../icon/icon\";\nimport { StyledButton } from \"./button-styles\";\nimport { BUTTON_INTENT, BUTTON_SIZE, BUTTON_VARIANT, ICON_POSITION } from \"./constants\";\nimport type { ButtonProps } from \"./types\";\n\n/** A versatile button component with multiple variants and sizes. */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(\n {\n children,\n variant = BUTTON_VARIANT.SOLID,\n intent = BUTTON_INTENT.PRIMARY,\n size = BUTTON_SIZE.M,\n icon,\n iconPosition = ICON_POSITION.LEADING,\n disabled = false,\n onClick,\n className,\n \"aria-label\": ariaLabel,\n },\n ref\n) {\n const iconElement = icon ? <Icon icon={icon} size={16} /> : null;\n\n return (\n <StyledButton\n ref={ref}\n type=\"button\"\n $variant={variant}\n $intent={intent}\n $size={size}\n disabled={disabled}\n onClick={disabled ? undefined : onClick}\n className={className}\n aria-label={ariaLabel}\n >\n {iconPosition === ICON_POSITION.LEADING && iconElement}\n <span>{children}</span>\n {iconPosition === ICON_POSITION.TRAILING && iconElement}\n </StyledButton>\n );\n});\n","import { forwardRef } from \"react\";\n\nimport { IconWrapper, getStrokeWidth } from \"./icon-styles\";\nimport type { IconProps } from \"./types\";\n\nconst DEFAULT_SIZE = 16;\n\nexport const Icon = forwardRef<HTMLSpanElement, IconProps>(function Icon(\n { icon: IconComponent, size = DEFAULT_SIZE, color, className, \"aria-label\": ariaLabel },\n ref\n) {\n return (\n <IconWrapper\n ref={ref}\n className={className}\n $color={color}\n aria-label={ariaLabel}\n role={ariaLabel ? \"img\" : undefined}\n >\n <IconComponent width={size} height={size} strokeWidth={getStrokeWidth(size)} />\n </IconWrapper>\n );\n});\n","import styled from \"styled-components\";\n\nexport const STROKE_WIDTH_BY_SIZE: Record<number, number> = {\n 12: 1.4,\n 14: 1.4,\n 16: 1.8,\n 18: 1.8,\n 20: 1.8,\n 24: 1.8,\n};\n\nexport const DEFAULT_STROKE_WIDTH = 1.8;\n\nexport function getStrokeWidth(size: number): number {\n return STROKE_WIDTH_BY_SIZE[size] ?? DEFAULT_STROKE_WIDTH;\n}\n\nexport const IconWrapper = styled.span<{ $color?: string }>`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: ${({ $color }) => $color ?? \"currentColor\"};\n flex-shrink: 0;\n`;\n","import styled, { css } from \"styled-components\";\nimport { colors } from \"../../tokens/colors\";\nimport { typographyMixin, typographyTypes } from \"../../tokens/typography\";\nimport { BUTTON_INTENT, BUTTON_SIZE, BUTTON_VARIANT } from \"./constants\";\nimport type { ButtonIntent, ButtonSize, ButtonVariant } from \"./types\";\n\ninterface IntentColors {\n /** Primary fill / text color. */\n base: string;\n /** Hover fill for solid variant. */\n hover: string;\n /** Muted fill for disabled solid variant. */\n disabledBg: string;\n /** Muted text for disabled state. */\n disabledText: string;\n /** Subtle hover background for outline/ghost variants. */\n subtleHover: string;\n /** Border color for outline variant. */\n border: string;\n /** Muted border for disabled outline variant. */\n disabledBorder: string;\n}\n\nconst intentColors: Record<ButtonIntent, IntentColors> = {\n [BUTTON_INTENT.PRIMARY]: {\n base: colors[\"brown-100\"],\n hover: colors[\"brown-90\"],\n disabledBg: colors[\"brown-20\"],\n disabledText: colors[\"brown-50\"],\n subtleHover: colors[\"brown-20\"],\n border: colors[\"brown-40\"],\n disabledBorder: colors[\"brown-20\"],\n },\n [BUTTON_INTENT.ERROR]: {\n base: colors[\"red-500\"],\n hover: colors[\"red-600\"],\n disabledBg: colors[\"red-100\"],\n disabledText: colors[\"red-200\"],\n subtleHover: colors[\"red-50\"],\n border: colors[\"red-200\"],\n disabledBorder: colors[\"red-100\"],\n },\n};\n\ninterface SizeValues {\n padding: string;\n borderRadius: string;\n gap: string;\n}\n\nconst sizeValues: Record<ButtonSize, SizeValues> = {\n [BUTTON_SIZE.XS]: { padding: \"6px 10px\", borderRadius: \"8px\", gap: \"4px\" },\n [BUTTON_SIZE.S]: { padding: \"8px 12px\", borderRadius: \"10px\", gap: \"6px\" },\n [BUTTON_SIZE.M]: { padding: \"10px 14px\", borderRadius: \"10px\", gap: \"6px\" },\n};\n\nfunction sizeMixin({ $size }: { $size: ButtonSize }): ReturnType<typeof css> {\n const s = sizeValues[$size];\n return css`\n padding: ${s.padding};\n border-radius: ${s.borderRadius};\n gap: ${s.gap};\n `;\n}\n\ninterface VariantColorMap {\n background: string;\n color: string;\n border: string;\n hoverBg: string;\n disabledBg?: string;\n disabledColor: string;\n disabledBorder?: string;\n}\n\nconst variantColorMap: Record<ButtonVariant, (c: IntentColors) => VariantColorMap> = {\n [BUTTON_VARIANT.SOLID]: (c) => ({\n background: c.base,\n color: colors.white,\n border: \"none\",\n hoverBg: c.hover,\n disabledBg: c.disabledBg,\n disabledColor: c.disabledText,\n }),\n [BUTTON_VARIANT.OUTLINE]: (c) => ({\n background: colors.white,\n color: c.base,\n border: `1px solid ${c.border}`,\n hoverBg: c.subtleHover,\n disabledColor: c.disabledText,\n disabledBorder: c.disabledBorder,\n }),\n [BUTTON_VARIANT.GHOST]: (c) => ({\n background: \"transparent\",\n color: c.base,\n border: \"none\",\n hoverBg: c.subtleHover,\n disabledColor: c.disabledText,\n }),\n};\n\nfunction variantMixin({\n $variant,\n $intent,\n}: {\n $variant: ButtonVariant;\n $intent: ButtonIntent;\n}): ReturnType<typeof css> {\n const v = variantColorMap[$variant](intentColors[$intent]);\n\n return css`\n background: ${v.background};\n color: ${v.color};\n border: ${v.border};\n\n &:hover:not(:disabled) {\n background: ${v.hoverBg};\n }\n\n &:disabled {\n color: ${v.disabledColor};\n ${v.disabledBg ? `background: ${v.disabledBg};` : \"\"}\n ${v.disabledBorder ? `border-color: ${v.disabledBorder};` : \"\"}\n }\n `;\n}\n\n/** Styled button element with variant, intent, and size transient props. */\nexport const StyledButton = styled.button<{\n $variant: ButtonVariant;\n $intent: ButtonIntent;\n $size: ButtonSize;\n}>`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n ${typographyMixin(typographyTypes.GEIST_BODY_XS_MEDIUM)};\n transition: background-color 150ms ease, border-color 150ms ease, color 150ms ease;\n\n &:disabled {\n cursor: not-allowed;\n }\n\n ${sizeMixin}\n ${variantMixin}\n`;\n","export const colors = {\n // White\n white: \"#FFFFFF\",\n \"white-alpha-85\": \"rgba(255, 255, 255, 0.85)\",\n \"white-alpha-40\": \"rgba(255, 255, 255, 0.40)\",\n\n // Brown\n \"brown-10\": \"#FAF9F8\",\n \"brown-20\": \"#F5F3F0\",\n \"brown-30\": \"#EEEBE5\",\n \"brown-40\": \"#E6E2DA\",\n \"brown-50\": \"#CFCBC4\",\n \"brown-60\": \"#A19E99\",\n \"brown-70\": \"#73716D\",\n \"brown-80\": \"#5C5A57\",\n \"brown-90\": \"#2E2D2C\",\n \"brown-100\": \"#171716\",\n \"brown-alpha-12\": \"rgba(23, 23, 22, 0.12)\",\n \"brown-alpha-20\": \"rgba(23, 23, 22, 0.20)\",\n \"brown-alpha-55\": \"rgba(23, 23, 22, 0.55)\",\n \"brown-alpha-70\": \"rgba(23, 23, 22, 0.70)\",\n \"brown-alpha-80\": \"rgba(23, 23, 22, 0.80)\",\n \"brown-alpha-90\": \"rgba(23, 23, 22, 0.90)\",\n\n // Fuchsia\n \"fuchsia-50\": \"#FAF5FF\",\n \"fuchsia-300\": \"#F0ABFC\",\n \"fuchsia-500\": \"#D946EF\",\n \"fuchsia-600\": \"#C026D3\",\n \"fuchsia-800\": \"#86198F\",\n\n // Pink\n \"pink-50\": \"#FDF2F8\",\n \"pink-400\": \"#F472B6\",\n \"pink-600\": \"#DB2777\",\n \"pink-800\": \"#9D174D\",\n\n // Violet\n \"violet-50\": \"#F5F3FF\",\n \"violet-400\": \"#A78BFA\",\n \"violet-600\": \"#7C3AED\",\n \"violet-800\": \"#5B21B6\",\n\n // Indigo\n \"indigo-50\": \"#EEF2FF\",\n \"indigo-400\": \"#818CF8\",\n \"indigo-500\": \"#6366F1\",\n \"indigo-600\": \"#4F46E5\",\n \"indigo-800\": \"#3730A3\",\n\n // Cyan\n \"cyan-50\": \"#E7FEFF\",\n \"cyan-300\": \"#67E8F9\",\n \"cyan-600\": \"#0891B2\",\n \"cyan-900\": \"#164E63\",\n\n // Teal\n \"teal-50\": \"#EBFDF9\",\n \"teal-300\": \"#5EEAD4\",\n \"teal-600\": \"#0D9488\",\n\n // Rose\n \"rose-400\": \"#FB7185\",\n\n // Purple\n \"purple-400\": \"#C084FC\",\n\n // Blue\n \"blue-50\": \"#EFF6FF\",\n \"blue-100\": \"#DBEAFE\",\n \"blue-300\": \"#93C5FD\",\n \"blue-400\": \"#60A5FA\",\n \"blue-600\": \"#2563EB\",\n \"blue-800\": \"#1E40AF\",\n\n // Sky\n \"sky-300\": \"#7DD3FC\",\n\n // Green\n \"green-50\": \"#ECF9F0\",\n \"green-100\": \"#D4F1D9\",\n \"green-400\": \"#3DC269\",\n \"green-700\": \"#277C43\",\n \"green-800\": \"#1C5930\",\n\n // Orange\n \"orange-50\": \"#FFF7ED\",\n \"orange-100\": \"#FFEDD5\",\n \"orange-200\": \"#FED7AA\",\n \"orange-500\": \"#F97316\",\n \"orange-600\": \"#EA580C\",\n\n // Red\n \"red-50\": \"#FEF2F2\",\n \"red-100\": \"#FEE2E2\",\n \"red-200\": \"#FECACA\",\n \"red-400\": \"#F7776C\",\n \"red-500\": \"#EF4444\",\n \"red-600\": \"#DC2626\",\n} as const;\n\nexport type ColorToken = keyof typeof colors;\n","/** Available font families in the Shapes.co design system. */\nexport const fontFamilies = {\n /** Geist — primary UI font for body text, labels, headings, and display. */\n GEIST: \"Geist\",\n /** Crimson Pro — editorial/serif font, mostly italic. Used for decorative headings and pull quotes. */\n CRIMSON_PRO: \"Crimson Pro\",\n} as const;\n\n/*\n * Type-name convention: `<FAMILY>_<ROLE>_<SIZE>_<WEIGHT>[_ITALIC]`. An italic style is marked by a\n * trailing `_ITALIC` suffix on the name (mirroring io-client's `styled-mixins/typography-mixin`);\n * names without it are upright. The suffix is the single source of truth in the NAME — the matching\n * `typographyStyles` entry still carries `fontStyle: \"italic\"`.\n */\n\nexport const typographyTypes = {\n // Geist Label Caption (12px)\n GEIST_LABEL_CAPTION_REGULAR: \"GEIST_LABEL_CAPTION_REGULAR\",\n GEIST_LABEL_CAPTION_MEDIUM: \"GEIST_LABEL_CAPTION_MEDIUM\",\n GEIST_LABEL_CAPTION_SEMI_BOLD: \"GEIST_LABEL_CAPTION_SEMI_BOLD\",\n\n // Geist Body Extra Small (14px)\n GEIST_BODY_XS_REGULAR: \"GEIST_BODY_XS_REGULAR\",\n GEIST_BODY_XS_MEDIUM: \"GEIST_BODY_XS_MEDIUM\",\n GEIST_BODY_XS_BOLD: \"GEIST_BODY_XS_BOLD\",\n\n // Geist Body Small (16px)\n GEIST_BODY_S_REGULAR: \"GEIST_BODY_S_REGULAR\",\n GEIST_BODY_S_MEDIUM: \"GEIST_BODY_S_MEDIUM\",\n GEIST_BODY_S_SEMI_BOLD: \"GEIST_BODY_S_SEMI_BOLD\",\n GEIST_BODY_S_BOLD: \"GEIST_BODY_S_BOLD\",\n\n // Geist Body Medium (18px)\n GEIST_BODY_M_LIGHT: \"GEIST_BODY_M_LIGHT\",\n GEIST_BODY_M_REGULAR: \"GEIST_BODY_M_REGULAR\",\n GEIST_BODY_M_MEDIUM: \"GEIST_BODY_M_MEDIUM\",\n GEIST_BODY_M_SEMI_BOLD: \"GEIST_BODY_M_SEMI_BOLD\",\n\n // Geist Body Large (20px)\n GEIST_BODY_L_REGULAR: \"GEIST_BODY_L_REGULAR\",\n GEIST_BODY_L_MEDIUM: \"GEIST_BODY_L_MEDIUM\",\n GEIST_BODY_L_SEMI_BOLD: \"GEIST_BODY_L_SEMI_BOLD\",\n GEIST_BODY_L_BOLD: \"GEIST_BODY_L_BOLD\",\n\n // Geist Heading Small (24px)\n GEIST_HEADING_S_REGULAR: \"GEIST_HEADING_S_REGULAR\",\n GEIST_HEADING_S_MEDIUM: \"GEIST_HEADING_S_MEDIUM\",\n GEIST_HEADING_S_BOLD: \"GEIST_HEADING_S_BOLD\",\n\n // Geist Heading Medium (28px)\n GEIST_HEADING_M_BOLD: \"GEIST_HEADING_M_BOLD\",\n\n // Geist Heading Large (32px)\n GEIST_HEADING_L_REGULAR: \"GEIST_HEADING_L_REGULAR\",\n GEIST_HEADING_L_MEDIUM: \"GEIST_HEADING_L_MEDIUM\",\n GEIST_HEADING_L_SEMI_BOLD: \"GEIST_HEADING_L_SEMI_BOLD\",\n GEIST_HEADING_L_BOLD: \"GEIST_HEADING_L_BOLD\",\n\n // Geist Display Large (36px)\n GEIST_DISPLAY_L_MEDIUM: \"GEIST_DISPLAY_L_MEDIUM\",\n\n // Crimson Pro Body Small (16px, italic)\n CRIMSON_PRO_BODY_S_LIGHT_ITALIC: \"CRIMSON_PRO_BODY_S_LIGHT_ITALIC\",\n\n // Crimson Pro Body Medium (18px, italic)\n CRIMSON_PRO_BODY_M_LIGHT_ITALIC: \"CRIMSON_PRO_BODY_M_LIGHT_ITALIC\",\n\n // Crimson Pro Heading Medium (24px, italic)\n CRIMSON_PRO_HEADING_M_MEDIUM_ITALIC: \"CRIMSON_PRO_HEADING_M_MEDIUM_ITALIC\",\n\n // Crimson Pro Display Large (40px, upright)\n CRIMSON_PRO_DISPLAY_L_REGULAR: \"CRIMSON_PRO_DISPLAY_L_REGULAR\",\n\n // Crimson Pro Display Extra Large (46px, italic)\n CRIMSON_PRO_DISPLAY_XL_REGULAR_ITALIC: \"CRIMSON_PRO_DISPLAY_XL_REGULAR_ITALIC\",\n} as const;\n\n/** Union of all typography type string constants. Used as keys into `typographyStyles`. */\nexport type TypographyType = (typeof typographyTypes)[keyof typeof typographyTypes];\n\n/** CSS properties for a single typography type. All numeric values are in pixels. */\nexport interface TypographyStyle {\n /** Font family name (e.g., \"Geist\"). */\n fontFamily: string;\n /** Font size in pixels. */\n fontSize: number;\n /** Font weight (100–900). */\n fontWeight: number;\n /** Line height in pixels. */\n lineHeight: number;\n /** Letter spacing in pixels. Omitted when the font's default spacing is correct. */\n letterSpacing?: number;\n /** CSS font-style value (e.g., \"italic\"). Omitted for normal style. */\n fontStyle?: string;\n}\n\nexport const typographyStyles: Record<TypographyType, TypographyStyle> = {\n // Geist Label Caption (12px)\n [typographyTypes.GEIST_LABEL_CAPTION_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 12,\n fontWeight: 400,\n lineHeight: 16,\n },\n [typographyTypes.GEIST_LABEL_CAPTION_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 12,\n fontWeight: 500,\n lineHeight: 16,\n },\n [typographyTypes.GEIST_LABEL_CAPTION_SEMI_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 12,\n fontWeight: 600,\n lineHeight: 16,\n },\n\n // Geist Body Extra Small (14px)\n [typographyTypes.GEIST_BODY_XS_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 14,\n fontWeight: 400,\n lineHeight: 20,\n },\n [typographyTypes.GEIST_BODY_XS_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 14,\n fontWeight: 500,\n lineHeight: 20,\n },\n [typographyTypes.GEIST_BODY_XS_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 14,\n fontWeight: 600,\n lineHeight: 20,\n },\n\n // Geist Body Small (16px)\n [typographyTypes.GEIST_BODY_S_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 16,\n fontWeight: 400,\n lineHeight: 24,\n letterSpacing: -0.08,\n },\n [typographyTypes.GEIST_BODY_S_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 16,\n fontWeight: 500,\n lineHeight: 24,\n letterSpacing: -0.08,\n },\n [typographyTypes.GEIST_BODY_S_SEMI_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 16,\n fontWeight: 600,\n lineHeight: 24,\n letterSpacing: -0.08,\n },\n [typographyTypes.GEIST_BODY_S_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 16,\n fontWeight: 700,\n lineHeight: 24,\n letterSpacing: -0.08,\n },\n\n // Geist Body Medium (18px)\n [typographyTypes.GEIST_BODY_M_LIGHT]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 18,\n fontWeight: 300,\n lineHeight: 28,\n letterSpacing: -0.09,\n },\n [typographyTypes.GEIST_BODY_M_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 18,\n fontWeight: 400,\n lineHeight: 28,\n letterSpacing: -0.09,\n },\n [typographyTypes.GEIST_BODY_M_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 18,\n fontWeight: 500,\n lineHeight: 28,\n letterSpacing: -0.09,\n },\n [typographyTypes.GEIST_BODY_M_SEMI_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 18,\n fontWeight: 600,\n lineHeight: 28,\n letterSpacing: -0.09,\n },\n\n // Geist Body Large (20px)\n [typographyTypes.GEIST_BODY_L_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 20,\n fontWeight: 400,\n lineHeight: 30,\n letterSpacing: -0.2,\n },\n [typographyTypes.GEIST_BODY_L_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 20,\n fontWeight: 500,\n lineHeight: 30,\n letterSpacing: -0.2,\n },\n [typographyTypes.GEIST_BODY_L_SEMI_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 20,\n fontWeight: 600,\n lineHeight: 30,\n letterSpacing: -0.2,\n },\n [typographyTypes.GEIST_BODY_L_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 20,\n fontWeight: 700,\n lineHeight: 30,\n letterSpacing: -0.2,\n },\n\n // Geist Heading Small (24px)\n [typographyTypes.GEIST_HEADING_S_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 24,\n fontWeight: 400,\n lineHeight: 32,\n letterSpacing: -0.48,\n },\n [typographyTypes.GEIST_HEADING_S_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 24,\n fontWeight: 500,\n lineHeight: 32,\n letterSpacing: -0.48,\n },\n [typographyTypes.GEIST_HEADING_S_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 24,\n fontWeight: 700,\n lineHeight: 32,\n letterSpacing: -0.48,\n },\n\n // Geist Heading Medium (28px)\n [typographyTypes.GEIST_HEADING_M_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 28,\n fontWeight: 700,\n lineHeight: 36,\n letterSpacing: -0.6,\n },\n\n // Geist Heading Large (32px)\n [typographyTypes.GEIST_HEADING_L_REGULAR]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 32,\n fontWeight: 400,\n lineHeight: 40,\n letterSpacing: -0.64,\n },\n [typographyTypes.GEIST_HEADING_L_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 32,\n fontWeight: 500,\n lineHeight: 40,\n letterSpacing: -0.64,\n },\n [typographyTypes.GEIST_HEADING_L_SEMI_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 32,\n fontWeight: 600,\n lineHeight: 40,\n letterSpacing: -0.64,\n },\n [typographyTypes.GEIST_HEADING_L_BOLD]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 32,\n fontWeight: 700,\n lineHeight: 40,\n letterSpacing: -0.64,\n },\n\n // Geist Display Large (36px)\n [typographyTypes.GEIST_DISPLAY_L_MEDIUM]: {\n fontFamily: fontFamilies.GEIST,\n fontSize: 36,\n fontWeight: 500,\n lineHeight: 44,\n letterSpacing: -0.72,\n },\n\n // Crimson Pro Body Small (16px, italic)\n [typographyTypes.CRIMSON_PRO_BODY_S_LIGHT_ITALIC]: {\n fontFamily: fontFamilies.CRIMSON_PRO,\n fontSize: 16,\n fontWeight: 300,\n lineHeight: 20,\n letterSpacing: -0.32,\n fontStyle: \"italic\",\n },\n\n // Crimson Pro Body Medium (18px, italic)\n [typographyTypes.CRIMSON_PRO_BODY_M_LIGHT_ITALIC]: {\n fontFamily: fontFamilies.CRIMSON_PRO,\n fontSize: 18,\n fontWeight: 300,\n lineHeight: 28,\n letterSpacing: 0,\n fontStyle: \"italic\",\n },\n\n // Crimson Pro Heading Medium (24px, italic)\n [typographyTypes.CRIMSON_PRO_HEADING_M_MEDIUM_ITALIC]: {\n fontFamily: fontFamilies.CRIMSON_PRO,\n fontSize: 24,\n fontWeight: 400,\n lineHeight: 32,\n letterSpacing: -0.48,\n fontStyle: \"italic\",\n },\n\n // Crimson Pro Display Large (40px, upright)\n [typographyTypes.CRIMSON_PRO_DISPLAY_L_REGULAR]: {\n fontFamily: fontFamilies.CRIMSON_PRO,\n fontSize: 40,\n fontWeight: 300,\n lineHeight: 48,\n letterSpacing: -1.6,\n },\n\n // Crimson Pro Display Extra Large (46px, italic)\n [typographyTypes.CRIMSON_PRO_DISPLAY_XL_REGULAR_ITALIC]: {\n fontFamily: fontFamilies.CRIMSON_PRO,\n fontSize: 46,\n fontWeight: 400,\n lineHeight: 54,\n letterSpacing: -1.38,\n fontStyle: \"italic\",\n },\n};\n\n/**\n * Generates a CSS string for a given typography type, suitable for use in styled-components template literals.\n * @param type - The typography type constant (e.g., `typographyTypes.GEIST_BODY_S_REGULAR`).\n * @returns A semicolon-separated CSS string with font-family, font-size, font-weight, line-height, letter-spacing, and font-style.\n */\nexport function typographyMixin(type: TypographyType): string {\n const style = typographyStyles[type];\n return [\n `font-family: \"${style.fontFamily}\", sans-serif`,\n `font-size: ${style.fontSize}px`,\n `font-weight: ${style.fontWeight}`,\n `line-height: ${style.lineHeight}px`,\n `letter-spacing: ${style.letterSpacing != null ? `${style.letterSpacing}px` : \"inherit\"}`,\n `font-style: ${style.fontStyle ?? \"normal\"}`,\n ].join(\";\\n \");\n}\n","/** Available visual style variants for the Button component. */\nexport const BUTTON_VARIANT = {\n SOLID: \"solid\",\n OUTLINE: \"outline\",\n GHOST: \"ghost\",\n} as const;\n\n/** Available size presets for the Button component. */\nexport const BUTTON_SIZE = {\n XS: \"xs\",\n S: \"s\",\n M: \"m\",\n} as const;\n\n/** Available semantic intents for the Button component. */\nexport const BUTTON_INTENT = {\n PRIMARY: \"primary\",\n ERROR: \"error\",\n} as const;\n\n/** Available icon positions relative to the label text. */\nexport const ICON_POSITION = {\n LEADING: \"leading\",\n TRAILING: \"trailing\",\n} as const;\n","import { forwardRef, useCallback, useLayoutEffect, useRef, type ChangeEvent } from \"react\";\n\nimport { mergeRefs } from \"@/utils/merge-refs\";\nimport { StyledTextArea } from \"./text-area-styles\";\nimport type { TextAreaProps } from \"./types\";\n\nexport const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(function TextArea(\n { value, onChange, placeholder, maxHeight, rows = 1, autoFocus, onKeyDown, disabled, className },\n externalRef\n) {\n const internalRef = useRef<HTMLTextAreaElement>(null);\n\n // Auto-resize: recalculates height whenever value changes so the textarea\n // grows/shrinks to fit its content (also restores correct height when the\n // component re-mounts or becomes visible again after being hidden).\n useLayoutEffect(() => {\n const el = internalRef.current;\n if (el) {\n el.style.height = \"auto\";\n el.style.height = `${el.scrollHeight}px`;\n }\n }, [value]);\n\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLTextAreaElement>) => {\n onChange(e.target.value);\n },\n [onChange]\n );\n\n return (\n <StyledTextArea\n ref={mergeRefs(internalRef, externalRef)}\n value={value}\n onChange={handleChange}\n placeholder={placeholder}\n $maxHeight={maxHeight}\n rows={rows}\n autoFocus={autoFocus}\n onKeyDown={onKeyDown}\n disabled={disabled}\n className={className}\n />\n );\n});\n","import type { Ref } from \"react\";\n\n/**\n * Combines multiple React refs into a single callback ref.\n * Useful when a component needs to forward its ref while also keeping a local ref.\n *\n * @param refs - Any number of React refs (callback refs, RefObjects, or `undefined`).\n * @returns A callback ref that updates all provided refs when the DOM node changes.\n */\nexport function mergeRefs<T>(...refs: (Ref<T> | undefined)[]): (node: T | null) => void {\n return (node) => {\n for (const ref of refs) {\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<T | null>).current = node;\n }\n }\n };\n}\n","import styled from \"styled-components\";\n\nimport { colors } from \"../../tokens/colors\";\nimport { typographyMixin, typographyTypes } from \"../../tokens/typography\";\n\nexport const StyledTextArea = styled.textarea<{ $maxHeight?: number }>`\n ${typographyMixin(typographyTypes.GEIST_BODY_S_REGULAR)};\n color: ${colors[\"brown-100\"]};\n border: none;\n outline: none;\n resize: none;\n width: 100%;\n background: transparent;\n vertical-align: bottom;\n max-height: ${({ $maxHeight }) => ($maxHeight ? `${$maxHeight}px` : \"none\")};\n overflow-y: ${({ $maxHeight }) => ($maxHeight ? \"auto\" : \"hidden\")};\n\n &::placeholder {\n color: ${colors[\"brown-50\"]};\n }\n\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n`;\n","import type { FormEvent, HTMLAttributes } from \"react\";\n\nimport type { TextAreaProps } from \"@/components/text-area/types\";\n\n/**\n * Submission status the submit button reflects. The composer has no cancellation and no\n * intermediate \"generating\" state of its own — the consumer disables the button while busy — so\n * only the idle and error states are modeled here.\n */\nexport const CHAT_STATUS = {\n /** Idle / ready to submit. */\n READY: \"ready\",\n /** The last submission errored — the button shows a retry affordance. */\n ERROR: \"error\",\n} as const;\n\n/** Submission status the submit button reflects. */\nexport type ChatStatus = (typeof CHAT_STATUS)[keyof typeof CHAT_STATUS];\n\n/** Payload emitted by {@link PromptInput} on submit. v1 carries only text (attachments are cut). */\nexport interface PromptInputMessage {\n /** The current textarea value at submit time. */\n text: string;\n}\n\n/** Props for the {@link PromptInput} form wrapper. */\nexport type PromptInputProps = Omit<HTMLAttributes<HTMLFormElement>, \"onSubmit\"> & {\n /**\n * Fired when the form is submitted (Enter key or the submit button) with non-empty text.\n * Receives the captured message and the underlying form event.\n */\n onSubmit: (message: PromptInputMessage, event: FormEvent<HTMLFormElement>) => void;\n /**\n * Blocks submission across every trigger (Enter key, submit button, programmatic) when `true` —\n * e.g. while a generation is in flight. The single gate that keeps the Enter path in sync with a\n * disabled submit button. @default false\n */\n disabled?: boolean;\n};\n\n/** Props for {@link PromptInputTextarea} — clay `TextArea` props; `className` styles the wrapper. */\nexport type PromptInputTextareaProps = TextAreaProps;\n\n/** Props for {@link PromptInputFooter}. */\nexport type PromptInputFooterProps = HTMLAttributes<HTMLDivElement>;\n\n/** Props for {@link PromptInputTools}. */\nexport type PromptInputToolsProps = HTMLAttributes<HTMLDivElement>;\n\n/** Props for {@link PromptInputSubmit}. */\nexport interface PromptInputSubmitProps {\n /** Button label — pass a localized string (i18n) from the consumer. @default \"Submit\" */\n label?: string;\n /** Drives the button color: `error` renders the red error intent, otherwise primary. @default \"ready\" */\n status?: ChatStatus;\n /** Whether the button is non-interactive (e.g. empty input or a generation in flight). */\n disabled?: boolean;\n /** Additional CSS class name. */\n className?: string;\n}\n","import { useEffect, useRef } from \"react\";\n\nimport { prefersReducedMotion } from \"@/utils/prefers-reduced-motion\";\n\nimport type { MouseGridProps } from \"./types\";\n\n/**\n * Absolutely-positioned grid backdrop, confined to its nearest positioned ancestor (give the\n * parent `position: relative` + `overflow: hidden` to clip it). The grid is revealed only near the\n * cursor via a radial mask whose center is driven by the `--vibe-mx` / `--vibe-my` CSS vars,\n * updated by a rAF-throttled `mousemove` listener. Renders behind all content (`z-0`) and never\n * blocks pointer events.\n *\n * Cursor coordinates are translated from viewport space (`clientX` / `clientY`) into layer-local\n * space (minus the layer's `getBoundingClientRect()` origin) and written onto the layer element\n * itself — not the document root — so the glow tracks correctly even though the layer no longer\n * fills the viewport. The rect read happens inside the rAF so it batches with paint.\n *\n * Pure `useEffect` + `requestAnimationFrame`, no animation library. The `.vibe-mouse-grid-layer` /\n * `.vibe-mouse-grid` / `.vibe-mouse-glow` styles ship in `@shapesos/clay/blocks/styles.css`.\n *\n * With `autoDrift`, a second rAF loop wanders the glow center along a slow sum-of-sines path\n * whenever the cursor is outside the layer; it yields the moment the cursor re-enters (the\n * mousemove handler owns the vars then) and resumes on exit. Suppressed under `prefers-reduced-motion`.\n *\n * When `glowColor` is an array of 2+ colors, a `setInterval` cycles the `--vibe-glow-color` var\n * through the list every `colorCycleMs`; the `.vibe-mouse-glow` `background-color` transition\n * (duration = `--vibe-glow-cycle`) crossfades between them. Also suppressed under\n * `prefers-reduced-motion` (first color applied flat).\n */\nexport function MouseGrid({ glowColor, colorCycleMs = 4000, autoDrift = false }: MouseGridProps = {}) {\n const layerRef = useRef<HTMLDivElement>(null);\n const glowRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n // Drift only runs when `autoDrift` is on AND motion isn't reduced. When it's off, the cursor is\n // tracked normally even outside the layer — so reduced-motion users don't get a frozen glow.\n const driftEnabled = autoDrift && !prefersReducedMotion();\n\n let raf = 0;\n let driftRaf = 0;\n let lastDriftTime = 0;\n let clientX = 0;\n let clientY = 0;\n let pointerInside = false;\n // Last applied glow center (layer-local px). Tracked across both modes so drift can resume from\n // wherever the cursor left off instead of snapping to the wander path's current value.\n let centerX = 0;\n let centerY = 0;\n let hasCenter = false;\n\n function setCenter(x: number, y: number) {\n const layer = layerRef.current;\n if (!layer) {\n return;\n }\n centerX = x;\n centerY = y;\n hasCenter = true;\n layer.style.setProperty(\"--vibe-mx\", `${x}px`);\n layer.style.setProperty(\"--vibe-my\", `${y}px`);\n }\n function flush() {\n raf = 0;\n const layer = layerRef.current;\n if (!layer) {\n return;\n }\n // While drift is active and the cursor is outside the layer, the drift loop owns the center —\n // don't let the (out-of-bounds) cursor position fight it. Otherwise always track the cursor.\n if (driftEnabled && !pointerInside) {\n return;\n }\n const rect = layer.getBoundingClientRect();\n setCenter(clientX - rect.left, clientY - rect.top);\n }\n function onMove(event: MouseEvent) {\n clientX = event.clientX;\n clientY = event.clientY;\n const layer = layerRef.current;\n if (layer) {\n const rect = layer.getBoundingClientRect();\n pointerInside =\n clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;\n }\n // Run the drift loop only when it has work to do (cursor outside) — pause it while inside.\n if (pointerInside) {\n stopDrift();\n } else {\n startDrift();\n }\n if (raf) {\n return;\n }\n raf = requestAnimationFrame(flush);\n }\n // The cursor can leave the layer without another `mousemove` ever firing — e.g. when the layer\n // fills the viewport (or Storybook's preview iframe) and the pointer exits it entirely. Reset\n // the flag on document exit so drift resumes instead of freezing at the last in-bounds frame.\n function onPointerLeave() {\n pointerInside = false;\n startDrift();\n }\n function drift(time: number) {\n // Frame-rate-independent ease: convert elapsed ms into a per-frame factor so the glow reaches\n // the wander target in the same wall-clock time at 60 Hz and 120 Hz (a fixed factor would be\n // ~2× snappier on high-refresh displays). First frame falls back to a ~60 Hz delta.\n const delta = lastDriftTime ? time - lastDriftTime : 16.67;\n lastDriftTime = time;\n driftRaf = requestAnimationFrame(drift);\n const layer = layerRef.current;\n if (!layer) {\n return;\n }\n const { width, height } = layer.getBoundingClientRect();\n if (!hasCenter) {\n centerX = width / 2;\n centerY = height / 2;\n }\n // Organic wander: two sines per axis, slow + offset, kept inside ~[6%, 94%] of the bounds.\n const targetX = width * (0.5 + 0.32 * Math.sin(time * 0.00037) + 0.12 * Math.sin(time * 0.00091));\n const targetY = height * (0.5 + 0.32 * Math.cos(time * 0.00041) + 0.12 * Math.sin(time * 0.0011));\n // ~0.04 per frame at 60 Hz, but resolution-stable. Lets drift resume continuously from the\n // cursor's exit point with no jump; the target moves far slower, so amplitude is intact.\n const alpha = 1 - Math.exp(-0.0025 * delta);\n setCenter(centerX + (targetX - centerX) * alpha, centerY + (targetY - centerY) * alpha);\n }\n function startDrift() {\n if (!driftEnabled || driftRaf) {\n return;\n }\n lastDriftTime = 0;\n driftRaf = requestAnimationFrame(drift);\n }\n function stopDrift() {\n if (driftRaf) {\n cancelAnimationFrame(driftRaf);\n driftRaf = 0;\n }\n }\n\n window.addEventListener(\"mousemove\", onMove, { passive: true });\n document.documentElement.addEventListener(\"mouseleave\", onPointerLeave);\n // No pointer has been seen yet → idle, so start drifting immediately when enabled.\n startDrift();\n return () => {\n window.removeEventListener(\"mousemove\", onMove);\n document.documentElement.removeEventListener(\"mouseleave\", onPointerLeave);\n if (raf) {\n cancelAnimationFrame(raf);\n }\n stopDrift();\n };\n }, [autoDrift]);\n\n // Normalize the single `glowColor` prop (a CSS color, a list of colors, or nothing) to an array,\n // then serialize it: an inline array literal is a fresh ref each render, so keying the effect on\n // the serialized content means only an actual color change re-runs it — not unrelated re-renders.\n const colorList = Array.isArray(glowColor) ? glowColor : glowColor != null ? [glowColor] : [];\n const glowColorsKey = JSON.stringify(colorList);\n\n // Single owner of `--vibe-glow-color`: applies the first/only color flat, and crossfades through\n // the list when there are 2+. Driving it from one effect (rather than a cycle vs. a React inline\n // style) lets teardown reliably remove the var so a stale cycled color can't stick when cycling\n // stops — it reverts to the CSS default instead.\n useEffect(() => {\n const glow = glowRef.current;\n if (!glow) {\n return;\n }\n const colors = (JSON.parse(glowColorsKey) as string[]).filter(Boolean);\n const staticColor = colors[0];\n if (staticColor) {\n // Apply the first/static color flat (cycle duration still 0ms) so it doesn't fade in.\n glow.style.setProperty(\"--vibe-glow-color\", staticColor);\n }\n const clearColor = () => glow.style.removeProperty(\"--vibe-glow-color\");\n if (colors.length < 2 || prefersReducedMotion()) {\n return staticColor ? clearColor : undefined;\n }\n // Enable the crossfade next frame, then advance the color on each interval. The transition\n // duration equals the interval, so the blob is always smoothly in transit between colors.\n let index = 0;\n const raf = requestAnimationFrame(() => glow.style.setProperty(\"--vibe-glow-cycle\", `${colorCycleMs}ms`));\n const timer = setInterval(() => {\n index = (index + 1) % colors.length;\n glow.style.setProperty(\"--vibe-glow-color\", colors[index]);\n }, colorCycleMs);\n return () => {\n cancelAnimationFrame(raf);\n clearInterval(timer);\n glow.style.removeProperty(\"--vibe-glow-cycle\");\n clearColor();\n };\n }, [glowColorsKey, colorCycleMs]);\n\n return (\n <div ref={layerRef} aria-hidden=\"true\" className=\"vibe-mouse-grid-layer\">\n <div className=\"vibe-mouse-grid\" />\n <div ref={glowRef} className=\"vibe-mouse-glow\" />\n </div>\n );\n}\n","/**\n * Whether the user has requested reduced motion via the OS / browser\n * (`(prefers-reduced-motion: reduce)`). SSR-safe — use it to gate any optional animation so it\n * doesn't run for users who've opted out.\n *\n * @returns `true` when reduced motion is requested; `false` otherwise (including non-browser /\n * `matchMedia`-less environments, where there's no preference to honor).\n */\nexport function prefersReducedMotion(): boolean {\n return typeof window !== \"undefined\" && typeof window.matchMedia === \"function\"\n ? window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n : false;\n}\n","import { useCallback } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\nimport type { SuggestionProps, SuggestionsProps } from \"./types\";\n\n/* ------------------------------------------------------------------------------------------------\n * Vendored + slimmed from `@vercel/ai-elements`'s `suggestion` registry entry. Upstream wraps the\n * pills in a shadcn `ScrollArea` and renders each as a shadcn `Button variant=\"outline\"`; clay has\n * neither, so this ships a dependency-free row (`flex flex-wrap`) of Tailwind-styled pills using\n * clay's named color tokens. Engine note: this is vendored ai-elements chrome, so it's Tailwind —\n * clay's `Button` is styled-components with fixed radii and can't produce this 12px pill.\n * ------------------------------------------------------------------------------------------------ */\n\n/**\n * A centered, wrapping row of {@link Suggestion} pills — e.g. starter prompts beneath a composer.\n * Compose `Suggestion` children inside.\n */\nexport const Suggestions = ({ className, ...props }: SuggestionsProps) => (\n <div className={cn(\"flex flex-wrap items-center justify-center gap-3\", className)} {...props} />\n);\n\n/**\n * A single tappable suggestion pill. Renders `children` if provided, otherwise the `suggestion`\n * text, and calls `onClick(suggestion)` when clicked.\n */\nexport const Suggestion = ({ suggestion, onClick, className, children, ...props }: SuggestionProps) => {\n const handleClick = useCallback(() => onClick?.(suggestion), [onClick, suggestion]);\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n className={cn(\n \"cursor-pointer whitespace-nowrap rounded-[12px] border border-brown-30 bg-white px-4 py-2 text-sm text-brown-100 transition-colors hover:bg-brown-10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brown-40\",\n className\n )}\n {...props}\n >\n {children ?? suggestion}\n </button>\n );\n};\n"],"mappings":"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","names":["import_react","import_react","styled","Icon","import_styled_components","styled","import_jsx_runtime","Button","import_react","import_styled_components","styled","import_jsx_runtime","TextArea","import_jsx_runtime","PromptInputTextarea","import_react","import_jsx_runtime","colors","import_react","import_jsx_runtime"]}
@@ -91,8 +91,27 @@ interface MouseGridProps {
91
91
  /**
92
92
  * Color of the cursor-following glow (any CSS color; include your own alpha for intensity).
93
93
  * Applied via the `--vibe-glow-color` CSS var. Defaults to a subtle violet accent when omitted.
94
+ *
95
+ * Pass an **array** of 2+ colors to make the blob smoothly crossfade through them, transitioning
96
+ * to the next every {@link MouseGridProps.colorCycleMs} and looping back to the first. A single
97
+ * string (or single-element array) is applied statically. Honors `prefers-reduced-motion`:
98
+ * cycling is suppressed and the first color is applied statically.
94
99
  */
95
- glowColor?: string;
100
+ glowColor?: string | string[];
101
+ /**
102
+ * Interval in milliseconds between color changes when {@link MouseGridProps.glowColor} is an array
103
+ * of 2+ colors. The crossfade spans this whole interval, so the color is always smoothly in
104
+ * transit. Defaults to `4000`. Ignored when `glowColor` isn't a cycling list.
105
+ */
106
+ colorCycleMs?: number;
107
+ /**
108
+ * When `true`, the glow drifts on its own around the area whenever the cursor is *outside* the
109
+ * layer (idle state), tracing a slow looping path. As soon as the cursor re-enters the layer the
110
+ * glow snaps back to following it; drift resumes once the cursor leaves again. Defaults to `false`
111
+ * (glow only ever follows the cursor). Honors `prefers-reduced-motion` — drift is suppressed when
112
+ * the user has requested reduced motion.
113
+ */
114
+ autoDrift?: boolean;
96
115
  }
97
116
 
98
117
  /**
@@ -109,8 +128,17 @@ interface MouseGridProps {
109
128
  *
110
129
  * Pure `useEffect` + `requestAnimationFrame`, no animation library. The `.vibe-mouse-grid-layer` /
111
130
  * `.vibe-mouse-grid` / `.vibe-mouse-glow` styles ship in `@shapesos/clay/blocks/styles.css`.
131
+ *
132
+ * With `autoDrift`, a second rAF loop wanders the glow center along a slow sum-of-sines path
133
+ * whenever the cursor is outside the layer; it yields the moment the cursor re-enters (the
134
+ * mousemove handler owns the vars then) and resumes on exit. Suppressed under `prefers-reduced-motion`.
135
+ *
136
+ * When `glowColor` is an array of 2+ colors, a `setInterval` cycles the `--vibe-glow-color` var
137
+ * through the list every `colorCycleMs`; the `.vibe-mouse-glow` `background-color` transition
138
+ * (duration = `--vibe-glow-cycle`) crossfades between them. Also suppressed under
139
+ * `prefers-reduced-motion` (first color applied flat).
112
140
  */
113
- declare function MouseGrid({ glowColor }?: MouseGridProps): react_jsx_runtime.JSX.Element;
141
+ declare function MouseGrid({ glowColor, colorCycleMs, autoDrift }?: MouseGridProps): react_jsx_runtime.JSX.Element;
114
142
 
115
143
  /** Props for the {@link Suggestions} container — a wrapping, centered row of suggestion pills. */
116
144
  type SuggestionsProps = ComponentProps<"div">;
@@ -91,8 +91,27 @@ interface MouseGridProps {
91
91
  /**
92
92
  * Color of the cursor-following glow (any CSS color; include your own alpha for intensity).
93
93
  * Applied via the `--vibe-glow-color` CSS var. Defaults to a subtle violet accent when omitted.
94
+ *
95
+ * Pass an **array** of 2+ colors to make the blob smoothly crossfade through them, transitioning
96
+ * to the next every {@link MouseGridProps.colorCycleMs} and looping back to the first. A single
97
+ * string (or single-element array) is applied statically. Honors `prefers-reduced-motion`:
98
+ * cycling is suppressed and the first color is applied statically.
94
99
  */
95
- glowColor?: string;
100
+ glowColor?: string | string[];
101
+ /**
102
+ * Interval in milliseconds between color changes when {@link MouseGridProps.glowColor} is an array
103
+ * of 2+ colors. The crossfade spans this whole interval, so the color is always smoothly in
104
+ * transit. Defaults to `4000`. Ignored when `glowColor` isn't a cycling list.
105
+ */
106
+ colorCycleMs?: number;
107
+ /**
108
+ * When `true`, the glow drifts on its own around the area whenever the cursor is *outside* the
109
+ * layer (idle state), tracing a slow looping path. As soon as the cursor re-enters the layer the
110
+ * glow snaps back to following it; drift resumes once the cursor leaves again. Defaults to `false`
111
+ * (glow only ever follows the cursor). Honors `prefers-reduced-motion` — drift is suppressed when
112
+ * the user has requested reduced motion.
113
+ */
114
+ autoDrift?: boolean;
96
115
  }
97
116
 
98
117
  /**
@@ -109,8 +128,17 @@ interface MouseGridProps {
109
128
  *
110
129
  * Pure `useEffect` + `requestAnimationFrame`, no animation library. The `.vibe-mouse-grid-layer` /
111
130
  * `.vibe-mouse-grid` / `.vibe-mouse-glow` styles ship in `@shapesos/clay/blocks/styles.css`.
131
+ *
132
+ * With `autoDrift`, a second rAF loop wanders the glow center along a slow sum-of-sines path
133
+ * whenever the cursor is outside the layer; it yields the moment the cursor re-enters (the
134
+ * mousemove handler owns the vars then) and resumes on exit. Suppressed under `prefers-reduced-motion`.
135
+ *
136
+ * When `glowColor` is an array of 2+ colors, a `setInterval` cycles the `--vibe-glow-color` var
137
+ * through the list every `colorCycleMs`; the `.vibe-mouse-glow` `background-color` transition
138
+ * (duration = `--vibe-glow-cycle`) crossfades between them. Also suppressed under
139
+ * `prefers-reduced-motion` (first color applied flat).
112
140
  */
113
- declare function MouseGrid({ glowColor }?: MouseGridProps): react_jsx_runtime.JSX.Element;
141
+ declare function MouseGrid({ glowColor, colorCycleMs, autoDrift }?: MouseGridProps): react_jsx_runtime.JSX.Element;
114
142
 
115
143
  /** Props for the {@link Suggestions} container — a wrapping, centered row of suggestion pills. */
116
144
  type SuggestionsProps = ComponentProps<"div">;
@@ -8,7 +8,7 @@ import {
8
8
  PromptInputTools,
9
9
  Suggestion,
10
10
  Suggestions
11
- } from "./chunk-BR5S37SC.js";
11
+ } from "./chunk-4VE6ZXXW.js";
12
12
  import "./chunk-7OYIDM42.js";
13
13
  import "./chunk-KNYB3RL7.js";
14
14
  import "./chunk-B4U37WIH.js";