@smartspace/chat-ui 1.14.4-dev.88aea18 → 1.14.4-dev.e6584f0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import MuiButton from '@mui/material/Button';
2
2
  import IconButton from '@mui/material/IconButton';
3
- import { Loader2, Cpu, ChevronDown, Check, Globe, Zap, SlidersHorizontal, X, Paperclip, Mic, Square, Send, Minimize2, AlertTriangle, FileImage, FileVideo, FileAudio, FileArchive, FileCode, FileSpreadsheet, Presentation, FileText, ChevronUp, ExternalLink, Download, ShieldAlert, Copy } from 'lucide-react';
4
- import * as React8 from 'react';
5
- import { createContext, forwardRef, useImperativeHandle, useRef, useState, useEffect, useMemo, useCallback, useContext, useSyncExternalStore } from 'react';
3
+ import { Loader2, ChevronDown, Check, Cpu, SlidersHorizontal, X, Globe, Zap, Paperclip, Mic, Square, Send, Minimize2, AlertTriangle, FileImage, FileVideo, FileAudio, FileArchive, FileCode, FileSpreadsheet, Presentation, FileText, ChevronUp, ExternalLink, Download, ShieldAlert, Copy } from 'lucide-react';
4
+ import * as React9 from 'react';
5
+ import React9__default, { createContext, forwardRef, useImperativeHandle, useRef, useState, useEffect, useMemo, useCallback, useContext, useSyncExternalStore } from 'react';
6
6
  import { createPortal } from 'react-dom';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
- import { useQuery, queryOptions, useQueryClient, useMutation, skipToken } from '@tanstack/react-query';
8
+ import { useQuery, queryOptions, useQueryClient, useMutation } from '@tanstack/react-query';
9
9
  import { toast } from 'sonner';
10
10
  import { ChatZod } from '@smartspace/api-client';
11
11
  import { z } from 'zod';
@@ -24,7 +24,6 @@ import '@milkdown/prose/inputrules';
24
24
  import { withJsonFormsControlProps, withJsonFormsLayoutProps, JsonForms, ResolvedJsonFormsDispatch } from '@jsonforms/react';
25
25
  import { rankWith, uiTypeIs, createAjv } from '@jsonforms/core';
26
26
  import { vanillaRenderers, vanillaCells } from '@jsonforms/vanilla-renderers';
27
- import { FormControl, InputLabel, Select, MenuItem, useTheme, Box, Skeleton as Skeleton$1 } from '@mui/material';
28
27
  import 'ace-builds/src-noconflict/ace';
29
28
  import 'ace-builds/src-noconflict/ext-language_tools';
30
29
  import 'ace-builds/src-noconflict/mode-json';
@@ -57,6 +56,7 @@ import relativeTime from 'dayjs/plugin/relativeTime';
57
56
  import utc from 'dayjs/plugin/utc';
58
57
  import { Slot } from '@radix-ui/react-slot';
59
58
  import { cva } from 'class-variance-authority';
59
+ import { useTheme, Box, Skeleton as Skeleton$1 } from '@mui/material';
60
60
 
61
61
  var __defProp = Object.defineProperty;
62
62
  var __export = (target, all5) => {
@@ -365,6 +365,19 @@ var MessageValueType = /* @__PURE__ */ ((MessageValueType2) => {
365
365
  MessageValueType2["INPUT"] = "Input";
366
366
  return MessageValueType2;
367
367
  })(MessageValueType || {});
368
+ var MessageResponseSourceType = /* @__PURE__ */ ((MessageResponseSourceType2) => {
369
+ MessageResponseSourceType2["BlobInternal"] = "BlobInternal";
370
+ MessageResponseSourceType2["WebExternal"] = "WebExternal";
371
+ MessageResponseSourceType2["File"] = "File";
372
+ MessageResponseSourceType2["URL"] = "URL";
373
+ return MessageResponseSourceType2;
374
+ })(MessageResponseSourceType || {});
375
+ var MessageAttribution = /* @__PURE__ */ ((MessageAttribution2) => {
376
+ MessageAttribution2["Supported"] = "supported";
377
+ MessageAttribution2["Partial"] = "partial";
378
+ MessageAttribution2["Unsupported"] = "unsupported";
379
+ return MessageAttribution2;
380
+ })(MessageAttribution || {});
368
381
 
369
382
  // src/domains/threads/queryKeys.ts
370
383
  var THREAD_LIST_PAGE_SIZE = 30;
@@ -587,9 +600,14 @@ var useThread = ({
587
600
  };
588
601
  var useThreadIsRunning = (workspaceId, threadId) => {
589
602
  const queryClient = useQueryClient();
603
+ const service = useChatService();
590
604
  const { data: detailThread } = useQuery({
591
- queryKey: threadsKeys.detail(workspaceId ?? "", threadId ?? ""),
592
- queryFn: skipToken
605
+ ...threadDetailOptions({
606
+ service,
607
+ workspaceId: workspaceId ?? "",
608
+ threadId: threadId ?? ""
609
+ }),
610
+ enabled: false
593
611
  });
594
612
  const listThread = workspaceId && threadId ? getThreadPlaceholderFromListCache(queryClient, workspaceId, threadId) : void 0;
595
613
  const { data: optimistic } = useQuery({
@@ -2430,6 +2448,31 @@ function useFlowRunVariables(flowRunId) {
2430
2448
  enabled: !!flowRunId
2431
2449
  });
2432
2450
  }
2451
+
2452
+ // src/chat-variables/renders/fieldStyles.ts
2453
+ var scaleFor = (surface) => surface === "form" ? "comfortable" : "dense";
2454
+ var fieldLabelClass = (scale) => `block truncate font-medium text-muted-foreground ${scale === "dense" ? "mb-1 text-xs" : "mb-1.5 text-sm"}`;
2455
+ var CONTROL_BASE = "rounded-md border bg-background text-foreground transition-colors placeholder:text-muted-foreground ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-60";
2456
+ var borderClass = (hasError) => hasError ? "border-destructive" : "border-input";
2457
+ var fieldControlClass = (scale, hasError) => `w-full ${CONTROL_BASE} ${borderClass(hasError)} ${scale === "dense" ? "px-2.5 py-1.5 text-xs" : "px-3 py-2 text-sm"}`;
2458
+ var fieldTriggerClass = (scale, hasError) => `w-full ${CONTROL_BASE} ${borderClass(
2459
+ hasError
2460
+ )} flex items-center justify-between gap-2 text-left ${scale === "dense" ? "h-8 px-2.5 text-xs" : "h-10 px-3 text-sm"}`;
2461
+ var fieldNumberClass = (scale, hasError) => `${CONTROL_BASE} ${borderClass(hasError)} tabular-nums ${scale === "dense" ? "h-8 w-20 px-2 text-xs" : "h-10 w-24 px-2.5 text-sm"}`;
2462
+ var fieldHintClass = "mt-1 text-xs text-muted-foreground";
2463
+ var fieldErrorClass = "mt-1 text-xs text-destructive";
2464
+ var fieldRowClass = "flex items-center justify-between gap-3";
2465
+ var fieldRowLabelClass = (scale) => `min-w-0 flex-1 truncate font-medium text-muted-foreground ${scale === "dense" ? "text-xs" : "text-sm"}`;
2466
+ var pillClass = (opts) => `flex h-8 shrink-0 items-center gap-1.5 rounded-full border px-2.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${opts.active ? "border-primary/30 bg-primary/10 text-primary" : "border-border/70 bg-transparent text-muted-foreground hover:bg-secondary"} ${opts.hasError ? "border-destructive text-destructive" : ""} ${opts.disabled ? "cursor-not-allowed opacity-60" : ""}`;
2467
+ var pillLabelClass = "max-w-[9rem] truncate";
2468
+ var pillValueClass = "max-w-[9rem] truncate text-foreground";
2469
+ var switchTrackClass = (on, disabled) => `peer inline-flex h-6 w-11 shrink-0 items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background ${on ? "bg-primary" : "bg-input"} ${disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"}`;
2470
+ var switchThumbClass = (on) => `pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform ${on ? "translate-x-5" : "translate-x-0"}`;
2471
+ var POPOVER_WIDTH_PX = 288;
2472
+ var POPOVER_MAX_HEIGHT_PX = 288;
2473
+ var popoverClass = "flex flex-col overflow-hidden rounded-xl border border-border bg-popover shadow-lg";
2474
+ var popoverRowClass = "flex w-full items-center gap-2.5 px-3 py-2 text-left transition-colors hover:bg-secondary/60";
2475
+ var popoverHeadingClass = "text-[10px] font-semibold uppercase tracking-wide text-muted-foreground";
2433
2476
  function iconFor(label) {
2434
2477
  const name = (label ?? "").toLowerCase();
2435
2478
  if (/search|web|browse|internet/.test(name)) return Globe;
@@ -2445,7 +2488,8 @@ var BooleanRenderer = ({
2445
2488
  errors,
2446
2489
  uischema,
2447
2490
  visible,
2448
- enabled
2491
+ enabled,
2492
+ config
2449
2493
  }) => {
2450
2494
  const onToggle = useCallback(() => {
2451
2495
  handleChange(path2, !data);
@@ -2456,13 +2500,17 @@ var BooleanRenderer = ({
2456
2500
  const hasError = !!errors && errors.length > 0;
2457
2501
  const isChecked = Boolean(data);
2458
2502
  const Icon = iconFor(label);
2503
+ const surface = (config ?? {}).surface ?? "form";
2504
+ const scale = scaleFor(surface);
2459
2505
  const tooltip = [label, description, hasError ? errors : null].filter(Boolean).join(" \u2014 ");
2460
- return /* @__PURE__ */ jsxs(
2506
+ const toggle = /* @__PURE__ */ jsx(
2461
2507
  "button",
2462
2508
  {
2463
2509
  id: `toggle-${path2}`,
2464
2510
  type: "button",
2465
- "aria-pressed": isChecked,
2511
+ role: surface === "bar" ? void 0 : "switch",
2512
+ "aria-pressed": surface === "bar" ? isChecked : void 0,
2513
+ "aria-checked": surface === "bar" ? void 0 : isChecked,
2466
2514
  "aria-label": label,
2467
2515
  title: tooltip || void 0,
2468
2516
  onClick: onToggle,
@@ -2472,16 +2520,28 @@ var BooleanRenderer = ({
2472
2520
  e.currentTarget.blur();
2473
2521
  }
2474
2522
  },
2475
- className: `boolean-switch flex h-8 shrink-0 items-center gap-1.5 rounded-full border px-2.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${isChecked ? "border-primary/30 bg-primary/10 text-primary" : "border-transparent bg-transparent text-muted-foreground hover:bg-secondary"} ${hasError ? "border-destructive text-destructive" : ""} ${isDisabled ? "cursor-not-allowed opacity-60" : ""}`,
2476
- children: [
2523
+ className: surface === "bar" ? `boolean-switch ${pillClass({
2524
+ active: isChecked,
2525
+ hasError,
2526
+ disabled: isDisabled
2527
+ })}` : switchTrackClass(isChecked, isDisabled),
2528
+ children: surface === "bar" ? /* @__PURE__ */ jsxs(Fragment, { children: [
2477
2529
  /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5 shrink-0" }),
2478
2530
  label && // Desktop-first: the app and the package each ship a full Tailwind
2479
- // build, so a base `hidden` can out-order `sm:inline`. `max-sm:hidden`
2480
- // is the form that survives both cascades.
2481
- /* @__PURE__ */ jsx("span", { className: "inline max-w-[9rem] truncate max-sm:hidden", children: label })
2482
- ]
2531
+ // build, so a base `hidden` can out-order `sm:inline`.
2532
+ // `max-sm:hidden` is the form that survives both cascades.
2533
+ /* @__PURE__ */ jsx("span", { className: `inline ${pillLabelClass} max-sm:hidden`, children: label })
2534
+ ] }) : /* @__PURE__ */ jsx("span", { className: switchThumbClass(isChecked) })
2483
2535
  }
2484
2536
  );
2537
+ if (surface === "bar") return toggle;
2538
+ return /* @__PURE__ */ jsxs("div", { className: "ss-jsonforms-field ss-jsonforms-boolean", children: [
2539
+ /* @__PURE__ */ jsxs("div", { className: fieldRowClass, children: [
2540
+ /* @__PURE__ */ jsx("label", { htmlFor: `toggle-${path2}`, className: fieldRowLabelClass(scale), children: label }),
2541
+ toggle
2542
+ ] }),
2543
+ hasError && /* @__PURE__ */ jsx("div", { className: fieldErrorClass, children: errors })
2544
+ ] });
2485
2545
  };
2486
2546
  var booleanRendererTester = rankWith(40, (uischema, schema) => {
2487
2547
  if (uischema.type !== "Control") return false;
@@ -2491,6 +2551,104 @@ var booleanRendererTester = rankWith(40, (uischema, schema) => {
2491
2551
  return fieldSchema?.type === "boolean";
2492
2552
  });
2493
2553
  var BooleanRendererControl = withJsonFormsControlProps(BooleanRenderer);
2554
+ var GAP_PX = 8;
2555
+ var MIN_TRIGGER_WIDTH_PX = 224;
2556
+ var MIN_PANEL_HEIGHT_PX = 180;
2557
+ var NestedPopoverContext = React9__default.createContext(null);
2558
+ function useAnchoredPopover({
2559
+ trigger,
2560
+ popover,
2561
+ width,
2562
+ maxHeight,
2563
+ role,
2564
+ label
2565
+ }) {
2566
+ const [isOpen, setIsOpen] = useState(false);
2567
+ const parentRegistry = useContext(NestedPopoverContext);
2568
+ const descendants = useRef(/* @__PURE__ */ new Set());
2569
+ const close = useCallback(() => setIsOpen(false), []);
2570
+ const toggle = useCallback(() => setIsOpen((open) => !open), []);
2571
+ const registry = useMemo(
2572
+ () => ({
2573
+ register: (el) => {
2574
+ descendants.current.add(el);
2575
+ parentRegistry?.register(el);
2576
+ },
2577
+ unregister: (el) => {
2578
+ descendants.current.delete(el);
2579
+ parentRegistry?.unregister(el);
2580
+ }
2581
+ }),
2582
+ [parentRegistry]
2583
+ );
2584
+ useEffect(() => {
2585
+ if (!isOpen || !parentRegistry) return;
2586
+ const el = popover.current;
2587
+ if (!el) return;
2588
+ parentRegistry.register(el);
2589
+ return () => parentRegistry.unregister(el);
2590
+ }, [isOpen, parentRegistry, popover]);
2591
+ useEffect(() => {
2592
+ if (!isOpen) return;
2593
+ const onPointerDown = (event) => {
2594
+ const target = event.target;
2595
+ if (trigger.current?.contains(target)) return;
2596
+ if (popover.current?.contains(target)) return;
2597
+ for (const el of descendants.current) {
2598
+ if (el.contains(target)) return;
2599
+ }
2600
+ close();
2601
+ };
2602
+ const onKeyDown = (event) => {
2603
+ if (event.key === "Escape") close();
2604
+ };
2605
+ document.addEventListener("mousedown", onPointerDown);
2606
+ document.addEventListener("keydown", onKeyDown);
2607
+ window.addEventListener("resize", close);
2608
+ return () => {
2609
+ document.removeEventListener("mousedown", onPointerDown);
2610
+ document.removeEventListener("keydown", onKeyDown);
2611
+ window.removeEventListener("resize", close);
2612
+ };
2613
+ }, [isOpen, close, trigger, popover]);
2614
+ const renderPopover = (children2) => {
2615
+ if (!isOpen) return null;
2616
+ const anchor = trigger.current?.getBoundingClientRect();
2617
+ if (!anchor) return null;
2618
+ const panelWidth = width === "trigger" ? Math.max(anchor.width, MIN_TRIGGER_WIDTH_PX) : width;
2619
+ const spaceAbove = anchor.top - GAP_PX * 2;
2620
+ const spaceBelow = window.innerHeight - anchor.bottom - GAP_PX * 2;
2621
+ const openAbove = spaceAbove >= MIN_PANEL_HEIGHT_PX || spaceAbove >= spaceBelow;
2622
+ const panelMaxHeight = Math.max(
2623
+ 0,
2624
+ Math.min(maxHeight, openAbove ? spaceAbove : spaceBelow)
2625
+ );
2626
+ return createPortal(
2627
+ /* @__PURE__ */ jsx(
2628
+ "div",
2629
+ {
2630
+ ref: popover,
2631
+ role,
2632
+ "aria-label": label,
2633
+ className: `fixed z-50 ${popoverClass}`,
2634
+ style: {
2635
+ width: panelWidth,
2636
+ maxWidth: `calc(100vw - ${GAP_PX * 4}px)`,
2637
+ left: Math.max(
2638
+ GAP_PX,
2639
+ Math.min(anchor.left, window.innerWidth - panelWidth - GAP_PX)
2640
+ ),
2641
+ ...openAbove ? { bottom: window.innerHeight - anchor.top + GAP_PX } : { top: anchor.bottom + GAP_PX },
2642
+ maxHeight: panelMaxHeight
2643
+ },
2644
+ children: /* @__PURE__ */ jsx(NestedPopoverContext.Provider, { value: registry, children: children2 })
2645
+ }
2646
+ ),
2647
+ document.body
2648
+ );
2649
+ };
2650
+ return { isOpen, close, toggle, renderPopover };
2651
+ }
2494
2652
  function hasConst(x) {
2495
2653
  return !!x && typeof x === "object" && "const" in x;
2496
2654
  }
@@ -2529,185 +2687,109 @@ var DropdownRenderer = ({
2529
2687
  label,
2530
2688
  description,
2531
2689
  errors,
2532
- uischema
2690
+ config,
2691
+ uischema,
2692
+ visible
2533
2693
  }) => {
2694
+ const triggerRef = useRef(null);
2695
+ const listRef = useRef(null);
2696
+ const surface = (config ?? {}).surface ?? "form";
2697
+ const scale = scaleFor(surface);
2698
+ const { isOpen, close, toggle, renderPopover } = useAnchoredPopover({
2699
+ trigger: triggerRef,
2700
+ popover: listRef,
2701
+ // A select's list lines up with its own control.
2702
+ width: "trigger",
2703
+ maxHeight: POPOVER_MAX_HEIGHT_PX,
2704
+ role: "listbox",
2705
+ label: label || "Options"
2706
+ });
2534
2707
  const options = toOptions(schema);
2535
- const handleSelectionChange = useCallback(
2536
- (event) => {
2537
- handleChange(path2, event.target.value);
2708
+ const select = useCallback(
2709
+ (value) => {
2710
+ handleChange(path2, value);
2711
+ close();
2538
2712
  },
2539
- [handleChange, path2]
2713
+ [handleChange, path2, close]
2540
2714
  );
2541
- const displayValue = data ?? "";
2715
+ if (!visible) return null;
2542
2716
  const readOnly = uischema?.access === "Read";
2543
2717
  const isDisabled = !enabled || readOnly;
2544
- return /* @__PURE__ */ jsxs(
2545
- FormControl,
2718
+ const hasError = !!errors;
2719
+ const selected = options.find((option) => option.const === data);
2720
+ const valueText = selected ? selected.title ?? String(selected.const) : data != null && data !== "" ? String(data) : "";
2721
+ const triggerId = `${path2}-trigger`;
2722
+ const isBar = surface === "bar";
2723
+ const placeholder = `Select ${(label || "value").toLowerCase()}\u2026`;
2724
+ const trigger = /* @__PURE__ */ jsxs(
2725
+ "button",
2546
2726
  {
2547
- variant: "outlined",
2548
- size: "small",
2549
- fullWidth: true,
2550
- error: !!errors,
2727
+ id: triggerId,
2728
+ ref: triggerRef,
2729
+ type: "button",
2551
2730
  disabled: isDisabled,
2552
- className: "compact-field",
2553
- sx: {
2554
- minWidth: "220px"
2555
- },
2731
+ onClick: toggle,
2732
+ "aria-haspopup": "listbox",
2733
+ "aria-expanded": isOpen,
2734
+ "aria-label": label,
2735
+ title: [label, valueText, hasError ? errors : null].filter(Boolean).join(" \u2014 ") || void 0,
2736
+ className: isBar ? `ss-jsonforms-select-trigger ${pillClass({
2737
+ active: isOpen,
2738
+ hasError,
2739
+ disabled: isDisabled
2740
+ })}` : `ss-jsonforms-select-trigger ${fieldTriggerClass(scale, hasError)}`,
2556
2741
  children: [
2742
+ isBar && label && /* @__PURE__ */ jsx("span", { className: `inline ${pillLabelClass} max-sm:hidden`, children: label }),
2557
2743
  /* @__PURE__ */ jsx(
2558
- InputLabel,
2744
+ "span",
2559
2745
  {
2560
- id: `${path2}-label`,
2561
- sx: {
2562
- color: "#6b7280",
2563
- fontSize: "0.875rem",
2564
- fontWeight: 500,
2565
- "&.Mui-focused": {
2566
- color: "#6366f1"
2567
- },
2568
- "&.Mui-error": {
2569
- color: "#ef4444"
2570
- }
2571
- },
2572
- children: label
2746
+ className: isBar ? pillValueClass : `min-w-0 flex-1 truncate ${valueText ? "" : "text-muted-foreground"}`,
2747
+ children: valueText || (isBar ? "\u2014" : placeholder)
2573
2748
  }
2574
2749
  ),
2575
2750
  /* @__PURE__ */ jsx(
2576
- Select,
2751
+ ChevronDown,
2577
2752
  {
2578
- labelId: `${path2}-label`,
2579
- value: displayValue,
2580
- onChange: handleSelectionChange,
2581
- label,
2582
- sx: {
2583
- "& .MuiOutlinedInput-root": {
2584
- backgroundColor: "#fafafa",
2585
- borderRadius: "8px",
2586
- transition: "all 0.2s ease-in-out",
2587
- height: "40px",
2588
- // Same height as model dropdown
2589
- "& fieldset": {
2590
- borderColor: "#e5e7eb",
2591
- borderWidth: "1px"
2592
- },
2593
- "&:hover": {
2594
- backgroundColor: "#ffffff",
2595
- "& fieldset": {
2596
- borderColor: "#9ca3af"
2597
- }
2598
- },
2599
- "&.Mui-focused": {
2600
- backgroundColor: "#ffffff",
2601
- "& fieldset": {
2602
- borderColor: "#6366f1",
2603
- borderWidth: "2px"
2604
- }
2605
- },
2606
- "&.Mui-error": {
2607
- "& fieldset": {
2608
- borderColor: "#ef4444"
2609
- }
2610
- }
2611
- },
2612
- "& .MuiSelect-select": {
2613
- backgroundColor: "#fafafa",
2614
- borderRadius: "8px",
2615
- transition: "all 0.2s ease-in-out",
2616
- height: "40px",
2617
- display: "flex",
2618
- alignItems: "center",
2619
- paddingRight: "32px !important",
2620
- "&:hover": {
2621
- backgroundColor: "#ffffff"
2622
- },
2623
- "&.Mui-focused": {
2624
- backgroundColor: "#ffffff"
2625
- }
2626
- },
2627
- "& .MuiOutlinedInput-notchedOutline": {
2628
- borderColor: "#e5e7eb",
2629
- borderWidth: "1px",
2630
- borderRadius: "8px"
2631
- },
2632
- "&:hover .MuiOutlinedInput-notchedOutline": {
2633
- borderColor: "#9ca3af"
2634
- },
2635
- "&.Mui-focused .MuiOutlinedInput-notchedOutline": {
2636
- borderColor: "#6366f1",
2637
- borderWidth: "2px"
2638
- },
2639
- "&.Mui-error .MuiOutlinedInput-notchedOutline": {
2640
- borderColor: "#ef4444"
2641
- },
2642
- "& .MuiSelect-icon": {
2643
- color: "#9ca3af",
2644
- "&:hover": {
2645
- color: "#6b7280"
2646
- }
2647
- }
2648
- },
2649
- MenuProps: {
2650
- PaperProps: {
2651
- sx: {
2652
- borderRadius: "8px",
2653
- boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
2654
- border: "1px solid #e5e7eb",
2655
- marginTop: "4px",
2656
- maxHeight: "280px"
2657
- }
2658
- },
2659
- MenuListProps: {
2660
- sx: {
2661
- padding: 0
2662
- }
2663
- }
2664
- },
2665
- children: options.map((option, index) => {
2666
- const raw2 = option.const;
2667
- const key = typeof raw2 === "string" || typeof raw2 === "number" ? String(raw2) : String(index);
2668
- const value = typeof raw2 === "string" || typeof raw2 === "number" ? raw2 : String(raw2 ?? index);
2669
- return /* @__PURE__ */ jsx(
2670
- MenuItem,
2671
- {
2672
- value,
2673
- sx: {
2674
- padding: "12px 16px",
2675
- fontSize: "0.875rem",
2676
- borderBottom: "1px solid #f3f4f6",
2677
- "&:last-child": {
2678
- borderBottom: "none"
2679
- },
2680
- "&:hover": {
2681
- backgroundColor: "#f8fafc"
2682
- },
2683
- "&.Mui-selected": {
2684
- backgroundColor: "#eff6ff",
2685
- "&:hover": {
2686
- backgroundColor: "#dbeafe"
2687
- }
2688
- }
2689
- },
2690
- children: option.title ?? String(raw2)
2691
- },
2692
- key
2693
- );
2694
- })
2695
- }
2696
- ),
2697
- (description || errors) && /* @__PURE__ */ jsx(
2698
- "div",
2699
- {
2700
- style: {
2701
- fontSize: "0.75rem",
2702
- marginTop: "4px",
2703
- color: errors ? "#ef4444" : "#6b7280"
2704
- },
2705
- children: errors || description
2753
+ className: `shrink-0 opacity-50 ${isBar ? "h-3 w-3" : "h-4 w-4"}`
2706
2754
  }
2707
2755
  )
2708
2756
  ]
2709
2757
  }
2710
2758
  );
2759
+ return /* @__PURE__ */ jsxs("div", { className: "ss-jsonforms-field ss-jsonforms-select compact-field", children: [
2760
+ !isBar && label && /* @__PURE__ */ jsx("label", { htmlFor: triggerId, className: fieldLabelClass(scale), children: label }),
2761
+ trigger,
2762
+ !isBar && (errors || description) && /* @__PURE__ */ jsx("div", { className: errors ? fieldErrorClass : fieldHintClass, children: errors || description }),
2763
+ renderPopover(
2764
+ /* @__PURE__ */ jsxs("div", { className: "min-h-0 overflow-y-auto py-1", children: [
2765
+ options.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-xs text-muted-foreground", children: "No options available" }),
2766
+ options.map((option, index) => {
2767
+ const active = option.const === data;
2768
+ const text6 = option.title ?? String(option.const);
2769
+ return /* @__PURE__ */ jsxs(
2770
+ "button",
2771
+ {
2772
+ type: "button",
2773
+ role: "option",
2774
+ "aria-selected": active,
2775
+ onClick: () => select(option.const),
2776
+ className: popoverRowClass,
2777
+ children: [
2778
+ /* @__PURE__ */ jsx(
2779
+ Check,
2780
+ {
2781
+ className: `h-3.5 w-3.5 shrink-0 ${active ? "text-primary" : "opacity-0"}`
2782
+ }
2783
+ ),
2784
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-sm text-foreground", children: text6 })
2785
+ ]
2786
+ },
2787
+ typeof option.const === "string" || typeof option.const === "number" ? String(option.const) : `option-${index}`
2788
+ );
2789
+ })
2790
+ ] })
2791
+ )
2792
+ ] });
2711
2793
  };
2712
2794
  var dropdownRendererTester = rankWith(
2713
2795
  90,
@@ -2725,8 +2807,8 @@ var dropdownRendererTester = rankWith(
2725
2807
  return false;
2726
2808
  }
2727
2809
  const hasDropdownOptions = !!(fieldSchema.oneOf || fieldSchema.anyOf || fieldSchema.enum && Array.isArray(fieldSchema.enum));
2728
- const isModelSelector = typeof fieldSchema === "object" && fieldSchema && fieldSchema["x-model-selector"] === true || fieldSchema.title === "ModelId" || fieldSchema.format === "uuid";
2729
- return hasDropdownOptions && !isModelSelector;
2810
+ const isModelSelector2 = typeof fieldSchema === "object" && fieldSchema && fieldSchema["x-model-selector"] === true || fieldSchema.title === "ModelId" || fieldSchema.format === "uuid";
2811
+ return hasDropdownOptions && !isModelSelector2;
2730
2812
  }
2731
2813
  );
2732
2814
  var DropdownRendererControl = withJsonFormsControlProps(DropdownRenderer);
@@ -2761,7 +2843,8 @@ var JsonEditorRenderer = ({
2761
2843
  uischema,
2762
2844
  visible,
2763
2845
  enabled,
2764
- required
2846
+ required,
2847
+ config
2765
2848
  }) => {
2766
2849
  const [jsonValue, setJsonValue] = useState("");
2767
2850
  const [displayedParseError, setDisplayedParseError] = useState(
@@ -2815,43 +2898,19 @@ var JsonEditorRenderer = ({
2815
2898
  }
2816
2899
  const readOnly = uischema?.access === "Read";
2817
2900
  const isDisabled = !enabled || readOnly;
2901
+ const scale = scaleFor(
2902
+ (config ?? {}).surface ?? "form"
2903
+ );
2818
2904
  return /* @__PURE__ */ jsxs("div", { style: { marginBottom: "1rem" }, children: [
2819
- label && /* @__PURE__ */ jsxs(
2820
- "label",
2821
- {
2822
- style: {
2823
- display: "block",
2824
- color: "#475569",
2825
- fontSize: "0.875rem",
2826
- fontWeight: 500,
2827
- marginBottom: "0.375rem"
2828
- },
2829
- children: [
2830
- label,
2831
- required && /* @__PURE__ */ jsx("span", { style: { color: "#ef4444", marginLeft: "0.25rem" }, children: "*" })
2832
- ]
2833
- }
2834
- ),
2835
- description && /* @__PURE__ */ jsx(
2836
- "div",
2837
- {
2838
- style: {
2839
- color: "#6b7280",
2840
- fontSize: "0.75rem",
2841
- marginBottom: "0.5rem"
2842
- },
2843
- children: description
2844
- }
2845
- ),
2905
+ label && /* @__PURE__ */ jsxs("label", { className: fieldLabelClass(scale), children: [
2906
+ label,
2907
+ required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-destructive", children: "*" })
2908
+ ] }),
2909
+ description && /* @__PURE__ */ jsx("div", { className: fieldHintClass, children: description }),
2846
2910
  /* @__PURE__ */ jsx(
2847
2911
  "div",
2848
2912
  {
2849
- style: {
2850
- border: errors || displayedParseError ? "1px solid #ef4444" : "1px solid #d1d5db",
2851
- borderRadius: "6px",
2852
- overflow: "hidden",
2853
- opacity: isDisabled ? 0.6 : 1
2854
- },
2913
+ className: `overflow-hidden rounded-md border ${errors || displayedParseError ? "border-destructive" : "border-input"} ${isDisabled ? "opacity-60" : ""}`,
2855
2914
  children: /* @__PURE__ */ jsx(
2856
2915
  AceEditor,
2857
2916
  {
@@ -2884,28 +2943,8 @@ var JsonEditorRenderer = ({
2884
2943
  )
2885
2944
  }
2886
2945
  ),
2887
- displayedParseError && /* @__PURE__ */ jsx(
2888
- "div",
2889
- {
2890
- style: {
2891
- color: "#ef4444",
2892
- fontSize: "0.75rem",
2893
- marginTop: "0.25rem"
2894
- },
2895
- children: displayedParseError
2896
- }
2897
- ),
2898
- errors && /* @__PURE__ */ jsx(
2899
- "div",
2900
- {
2901
- style: {
2902
- color: "#ef4444",
2903
- fontSize: "0.75rem",
2904
- marginTop: "0.25rem"
2905
- },
2906
- children: errors
2907
- }
2908
- )
2946
+ displayedParseError && /* @__PURE__ */ jsx("div", { className: fieldErrorClass, children: displayedParseError }),
2947
+ errors && /* @__PURE__ */ jsx("div", { className: fieldErrorClass, children: errors })
2909
2948
  ] });
2910
2949
  };
2911
2950
  var jsonEditorTester = rankWith(
@@ -2996,14 +3035,31 @@ var ModelIdRenderer = ({
2996
3035
  description,
2997
3036
  errors,
2998
3037
  uischema,
2999
- visible
3038
+ visible,
3039
+ config
3000
3040
  }) => {
3001
- const [isOpen, setIsOpen] = useState(false);
3002
3041
  const [searchValue, setSearchValue] = useState("");
3003
3042
  const [debouncedSearchValue, setDebouncedSearchValue] = useState("");
3004
- const containerRef = useRef(null);
3043
+ const triggerRef = useRef(null);
3005
3044
  const menuRef = useRef(null);
3006
3045
  const searchRef = useRef(null);
3046
+ const surface = (config ?? {}).surface ?? "bar";
3047
+ const scale = scaleFor(surface);
3048
+ const isBar = surface === "bar";
3049
+ const {
3050
+ isOpen,
3051
+ close: closeMenu,
3052
+ toggle,
3053
+ renderPopover
3054
+ } = useAnchoredPopover({
3055
+ trigger: triggerRef,
3056
+ popover: menuRef,
3057
+ // Wide enough for a provider glyph, a model name and its id underneath.
3058
+ width: POPOVER_WIDTH_PX,
3059
+ maxHeight: POPOVER_MAX_HEIGHT_PX,
3060
+ role: "listbox",
3061
+ label: "Models"
3062
+ });
3007
3063
  const debounceTimerRef = useRef(
3008
3064
  void 0
3009
3065
  );
@@ -3042,35 +3098,13 @@ var ModelIdRenderer = ({
3042
3098
  handleChange(path2, model.id);
3043
3099
  setSearchValue("");
3044
3100
  setDebouncedSearchValue("");
3045
- setIsOpen(false);
3101
+ closeMenu();
3046
3102
  },
3047
- [handleChange, path2]
3103
+ [handleChange, path2, closeMenu]
3048
3104
  );
3049
- const close = useCallback(() => {
3050
- setIsOpen(false);
3051
- setSearchValue("");
3052
- }, []);
3053
3105
  useEffect(() => {
3054
- if (!isOpen) return;
3055
- const onPointerDown = (event) => {
3056
- const target = event.target;
3057
- if (containerRef.current && !containerRef.current.contains(target) && !(menuRef.current && menuRef.current.contains(target))) {
3058
- close();
3059
- }
3060
- };
3061
- const onKeyDown = (event) => {
3062
- if (event.key === "Escape") close();
3063
- };
3064
- const onResize = () => close();
3065
- document.addEventListener("mousedown", onPointerDown);
3066
- document.addEventListener("keydown", onKeyDown);
3067
- window.addEventListener("resize", onResize);
3068
- return () => {
3069
- document.removeEventListener("mousedown", onPointerDown);
3070
- document.removeEventListener("keydown", onKeyDown);
3071
- window.removeEventListener("resize", onResize);
3072
- };
3073
- }, [isOpen, close]);
3106
+ if (!isOpen) setSearchValue("");
3107
+ }, [isOpen]);
3074
3108
  useEffect(() => {
3075
3109
  if (isOpen) searchRef.current?.focus();
3076
3110
  }, [isOpen]);
@@ -3079,53 +3113,58 @@ var ModelIdRenderer = ({
3079
3113
  const isDisabled = !enabled || readOnly;
3080
3114
  const hasError = !!errors && errors.length > 0;
3081
3115
  const selectedName = selectedModel ? selectedModel.displayName || selectedModel.name || "" : "";
3082
- const triggerText = selectedName || label || "Select model";
3116
+ const triggerText = selectedName || "Select model";
3083
3117
  const iconSrc = getModelIcon(selectedModel);
3084
3118
  const tooltip = [selectedName || label, description, hasError ? errors : null].filter(Boolean).join(" \u2014 ");
3085
- const anchorRect = isOpen ? containerRef.current?.getBoundingClientRect() : void 0;
3086
- return /* @__PURE__ */ jsxs("div", { className: "relative shrink-0", ref: containerRef, children: [
3087
- /* @__PURE__ */ jsxs(
3088
- "button",
3089
- {
3090
- type: "button",
3091
- onClick: () => setIsOpen((v) => !v),
3092
- disabled: isDisabled,
3093
- "aria-expanded": isOpen,
3094
- "aria-haspopup": "listbox",
3095
- "aria-label": label || "Select model",
3096
- title: tooltip || void 0,
3097
- className: `flex h-8 shrink-0 items-center gap-1.5 rounded-full border px-2.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${isOpen ? "border-primary/30 bg-primary/10 text-primary" : "border-border/70 bg-transparent text-muted-foreground hover:bg-secondary"} ${hasError ? "border-destructive text-destructive" : ""} ${isDisabled ? "cursor-not-allowed opacity-60" : ""}`,
3098
- children: [
3099
- iconSrc ? /* @__PURE__ */ jsx(
3100
- "img",
3101
- {
3102
- src: iconSrc,
3103
- alt: "",
3104
- className: "h-3.5 w-3.5 shrink-0 object-contain"
3105
- }
3106
- ) : /* @__PURE__ */ jsx(Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
3107
- /* @__PURE__ */ jsx("span", { className: "inline max-w-[9rem] truncate max-sm:hidden", children: triggerText }),
3108
- /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 shrink-0 opacity-60" })
3109
- ]
3110
- }
3111
- ),
3112
- isOpen && anchorRect && createPortal(
3113
- /* @__PURE__ */ jsxs(
3114
- "div",
3115
- {
3116
- ref: menuRef,
3117
- role: "listbox",
3118
- "aria-label": label || "Models",
3119
- className: "fixed z-50 w-72 max-w-[calc(100vw-2rem)] overflow-hidden rounded-xl border border-border bg-popover shadow-lg",
3120
- style: {
3121
- left: Math.max(
3122
- 8,
3123
- Math.min(anchorRect.left, window.innerWidth - 288 - 8)
3124
- ),
3125
- bottom: window.innerHeight - anchorRect.top + 8
3126
- },
3127
- children: [
3128
- /* @__PURE__ */ jsx("div", { className: "border-b border-border p-2", children: /* @__PURE__ */ jsx(
3119
+ const triggerLabel = !label || label === "ModelId" ? "Model" : label;
3120
+ const trigger = /* @__PURE__ */ jsxs(
3121
+ "button",
3122
+ {
3123
+ ref: triggerRef,
3124
+ id: `${path2}-trigger`,
3125
+ type: "button",
3126
+ onClick: toggle,
3127
+ disabled: isDisabled,
3128
+ "aria-expanded": isOpen,
3129
+ "aria-haspopup": "listbox",
3130
+ "aria-label": triggerLabel,
3131
+ title: tooltip || void 0,
3132
+ className: isBar ? pillClass({ active: isOpen, hasError, disabled: isDisabled }) : fieldTriggerClass(scale, hasError),
3133
+ children: [
3134
+ iconSrc ? /* @__PURE__ */ jsx(
3135
+ "img",
3136
+ {
3137
+ src: iconSrc,
3138
+ alt: "",
3139
+ className: "h-3.5 w-3.5 shrink-0 object-contain"
3140
+ }
3141
+ ) : /* @__PURE__ */ jsx(Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
3142
+ /* @__PURE__ */ jsx(
3143
+ "span",
3144
+ {
3145
+ className: isBar ? `inline ${pillValueClass} max-sm:hidden` : "min-w-0 flex-1 truncate",
3146
+ children: triggerText
3147
+ }
3148
+ ),
3149
+ /* @__PURE__ */ jsx(
3150
+ ChevronDown,
3151
+ {
3152
+ className: `shrink-0 opacity-60 ${isBar ? "h-3 w-3" : "h-4 w-4"}`
3153
+ }
3154
+ )
3155
+ ]
3156
+ }
3157
+ );
3158
+ return /* @__PURE__ */ jsxs(
3159
+ "div",
3160
+ {
3161
+ className: isBar ? "ss-jsonforms-field ss-jsonforms-model relative shrink-0" : "ss-jsonforms-field ss-jsonforms-model compact-field",
3162
+ children: [
3163
+ !isBar && /* @__PURE__ */ jsx("label", { htmlFor: `${path2}-trigger`, className: fieldLabelClass(scale), children: triggerLabel }),
3164
+ trigger,
3165
+ renderPopover(
3166
+ /* @__PURE__ */ jsxs(Fragment, { children: [
3167
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b border-border p-2", children: /* @__PURE__ */ jsx(
3129
3168
  "input",
3130
3169
  {
3131
3170
  ref: searchRef,
@@ -3137,7 +3176,7 @@ var ModelIdRenderer = ({
3137
3176
  className: "h-8 w-full rounded-md border border-border bg-background px-2 text-xs text-foreground outline-none placeholder:text-muted-foreground focus:border-primary/40"
3138
3177
  }
3139
3178
  ) }),
3140
- /* @__PURE__ */ jsxs("div", { className: "max-h-72 overflow-y-auto", children: [
3179
+ /* @__PURE__ */ jsxs("div", { className: "min-h-0 overflow-y-auto", children: [
3141
3180
  isLoading && listModels.length === 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-6", children: /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin text-primary" }) }),
3142
3181
  !isLoading && listModels.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-xs text-muted-foreground", children: searchValue ? "No models found" : "No models available" }),
3143
3182
  listModels.map((model) => {
@@ -3150,7 +3189,7 @@ var ModelIdRenderer = ({
3150
3189
  role: "option",
3151
3190
  "aria-selected": active,
3152
3191
  onClick: () => handleSelect(model),
3153
- className: "flex w-full items-center gap-2.5 px-3 py-2 text-left transition-colors hover:bg-secondary/60",
3192
+ className: popoverRowClass,
3154
3193
  children: [
3155
3194
  /* @__PURE__ */ jsx(
3156
3195
  Check,
@@ -3176,12 +3215,11 @@ var ModelIdRenderer = ({
3176
3215
  );
3177
3216
  })
3178
3217
  ] })
3179
- ]
3180
- }
3181
- ),
3182
- document.body
3183
- )
3184
- ] });
3218
+ ] })
3219
+ )
3220
+ ]
3221
+ }
3222
+ );
3185
3223
  };
3186
3224
  var modelIdRendererTester = rankWith(
3187
3225
  100,
@@ -3216,6 +3254,7 @@ var NumberRenderer = ({
3216
3254
  uischema,
3217
3255
  visible,
3218
3256
  enabled,
3257
+ config,
3219
3258
  required
3220
3259
  }) => {
3221
3260
  const isInteger = schema?.type === "integer";
@@ -3244,40 +3283,58 @@ var NumberRenderer = ({
3244
3283
  const max = fieldSchema?.maximum;
3245
3284
  const step = isInteger ? 1 : fieldSchema?.multipleOf ?? "any";
3246
3285
  const tooltip = [label, description, hasError ? errors : null].filter(Boolean).join(" \u2014 ");
3247
- return /* @__PURE__ */ jsxs(
3248
- "div",
3286
+ const surface = (config ?? {}).surface ?? "form";
3287
+ const scale = scaleFor(surface);
3288
+ const input = /* @__PURE__ */ jsx(
3289
+ "input",
3249
3290
  {
3250
- className: `ss-jsonforms-field ss-jsonforms-number flex h-8 shrink-0 items-center gap-1.5 rounded-full border px-2.5 text-xs font-medium transition-colors focus-within:border-primary/40 ${hasError ? "border-destructive" : "border-border/70"} ${isDisabled ? "opacity-60" : ""}`,
3251
- title: tooltip || void 0,
3252
- children: [
3253
- label && /* @__PURE__ */ jsxs(
3254
- "label",
3255
- {
3256
- htmlFor: `number-${path2}`,
3257
- className: `whitespace-nowrap ${hasError ? "text-destructive" : "text-muted-foreground"}`,
3258
- children: [
3259
- label,
3260
- required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-destructive", children: "*" })
3261
- ]
3262
- }
3263
- ),
3264
- /* @__PURE__ */ jsx(
3265
- "input",
3266
- {
3267
- id: `number-${path2}`,
3268
- type: "number",
3269
- value: data ?? "",
3270
- onChange: handleInputChange,
3271
- disabled: isDisabled,
3272
- min,
3273
- max,
3274
- step,
3275
- className: "w-14 border-0 bg-transparent p-0 text-xs font-medium tabular-nums text-foreground outline-none disabled:cursor-not-allowed"
3276
- }
3277
- )
3278
- ]
3291
+ id: `number-${path2}`,
3292
+ type: "number",
3293
+ value: data ?? "",
3294
+ onChange: handleInputChange,
3295
+ disabled: isDisabled,
3296
+ min,
3297
+ max,
3298
+ step,
3299
+ className: surface === "bar" ? "w-14 border-0 bg-transparent p-0 text-xs font-medium tabular-nums text-foreground outline-none disabled:cursor-not-allowed" : fieldNumberClass(scale, hasError)
3279
3300
  }
3280
3301
  );
3302
+ if (surface === "bar") {
3303
+ return /* @__PURE__ */ jsxs(
3304
+ "div",
3305
+ {
3306
+ className: `ss-jsonforms-field ss-jsonforms-number ${pillClass({
3307
+ hasError,
3308
+ disabled: isDisabled
3309
+ })}`,
3310
+ title: tooltip || void 0,
3311
+ children: [
3312
+ label && /* @__PURE__ */ jsxs(
3313
+ "label",
3314
+ {
3315
+ htmlFor: `number-${path2}`,
3316
+ className: `${pillLabelClass} whitespace-nowrap ${hasError ? "text-destructive" : "text-muted-foreground"}`,
3317
+ children: [
3318
+ label,
3319
+ required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-destructive", children: "*" })
3320
+ ]
3321
+ }
3322
+ ),
3323
+ input
3324
+ ]
3325
+ }
3326
+ );
3327
+ }
3328
+ return /* @__PURE__ */ jsxs("div", { className: "ss-jsonforms-field ss-jsonforms-number", children: [
3329
+ /* @__PURE__ */ jsxs("div", { className: fieldRowClass, children: [
3330
+ /* @__PURE__ */ jsxs("label", { htmlFor: `number-${path2}`, className: fieldRowLabelClass(scale), children: [
3331
+ label,
3332
+ required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-destructive", children: "*" })
3333
+ ] }),
3334
+ input
3335
+ ] }),
3336
+ hasError && /* @__PURE__ */ jsx("div", { className: fieldErrorClass, children: errors })
3337
+ ] });
3281
3338
  };
3282
3339
  var numberRendererTester = rankWith(
3283
3340
  40,
@@ -3293,6 +3350,14 @@ var numberRendererTester = rankWith(
3293
3350
  }
3294
3351
  );
3295
3352
  var NumberRendererControl = withJsonFormsControlProps(NumberRenderer);
3353
+ var SCALE = {
3354
+ comfortable: { lineHeight: 20, padding: 8 },
3355
+ dense: { lineHeight: 16, padding: 6 }
3356
+ };
3357
+ var rowsToPx = (rows, scale) => rows * scale.lineHeight + scale.padding * 2 + 2;
3358
+ var MAX_VIEWPORT_SHARE = 0.5;
3359
+ var DEFAULT_MIN_ROWS = 3;
3360
+ var DEFAULT_MAX_ROWS = 9;
3296
3361
  var TextareaRenderer = ({
3297
3362
  data,
3298
3363
  handleChange,
@@ -3304,28 +3369,49 @@ var TextareaRenderer = ({
3304
3369
  uischema,
3305
3370
  visible,
3306
3371
  enabled,
3307
- required
3372
+ required,
3373
+ config
3308
3374
  }) => {
3309
3375
  const textareaRef = useRef(null);
3376
+ const textareaOptions = schema["ui:textarea"] ?? {};
3377
+ const formConfig = config ?? {};
3378
+ const scaleName = scaleFor(formConfig.surface ?? "form");
3379
+ const scale = SCALE[scaleName];
3380
+ const minRows = textareaOptions.minRows ?? formConfig.minRows ?? DEFAULT_MIN_ROWS;
3381
+ const maxRows = Math.max(
3382
+ minRows,
3383
+ textareaOptions.maxRows ?? formConfig.maxRows ?? DEFAULT_MAX_ROWS
3384
+ );
3385
+ const minHeight = rowsToPx(minRows, scale);
3386
+ const maxHeight = rowsToPx(maxRows, scale);
3387
+ const [viewportCap, setViewportCap] = useState(
3388
+ () => typeof window === "undefined" ? Number.POSITIVE_INFINITY : Math.round(window.innerHeight * MAX_VIEWPORT_SHARE)
3389
+ );
3390
+ const ceiling = Math.max(minHeight, Math.min(maxHeight, viewportCap));
3310
3391
  const autoResize = useCallback(() => {
3311
- if (textareaRef.current) {
3312
- textareaRef.current.style.height = "auto";
3313
- textareaRef.current.style.height = `${Math.min(
3314
- Math.max(textareaRef.current.scrollHeight, 80),
3315
- // Minimum height of 80px
3316
- 240
3317
- // Maximum height of 240px
3318
- )}px`;
3319
- }
3320
- }, []);
3392
+ const el = textareaRef.current;
3393
+ if (!el) return;
3394
+ el.style.height = "auto";
3395
+ el.style.height = `${Math.min(
3396
+ Math.max(el.scrollHeight, minHeight),
3397
+ ceiling
3398
+ )}px`;
3399
+ }, [minHeight, ceiling]);
3321
3400
  useEffect(() => {
3322
3401
  autoResize();
3323
3402
  }, [data, autoResize]);
3403
+ useEffect(() => {
3404
+ const onResize = () => {
3405
+ setViewportCap(Math.round(window.innerHeight * MAX_VIEWPORT_SHARE));
3406
+ autoResize();
3407
+ };
3408
+ window.addEventListener("resize", onResize);
3409
+ return () => window.removeEventListener("resize", onResize);
3410
+ }, [autoResize]);
3324
3411
  const handleInputChange = useCallback(
3325
3412
  (event) => {
3326
- const newValue = event.target.value;
3327
- handleChange(path2, newValue);
3328
- setTimeout(autoResize, 0);
3413
+ handleChange(path2, event.target.value);
3414
+ autoResize();
3329
3415
  },
3330
3416
  [handleChange, path2, autoResize]
3331
3417
  );
@@ -3335,89 +3421,34 @@ var TextareaRenderer = ({
3335
3421
  const readOnly = uischema?.access === "Read";
3336
3422
  const isDisabled = !enabled || readOnly;
3337
3423
  const hasError = errors && errors.length > 0;
3338
- const textareaOptions = schema["ui:textarea"] ?? {};
3339
3424
  const placeholder = textareaOptions.placeholder || schema?.description || `Enter ${label?.toLowerCase() || "text"}...`;
3340
- const minRows = textareaOptions.minRows || 3;
3341
3425
  return /* @__PURE__ */ jsxs("div", { className: "ss-jsonforms-field ss-jsonforms-textarea", children: [
3342
- label && /* @__PURE__ */ jsxs(
3343
- "label",
3344
- {
3345
- style: {
3346
- display: "block",
3347
- color: hasError ? "#ef4444" : "#475569",
3348
- fontSize: "0.875rem",
3349
- fontWeight: 500,
3350
- marginBottom: "0.375rem"
3351
- },
3352
- children: [
3353
- label,
3354
- required && /* @__PURE__ */ jsx("span", { style: { color: "#ef4444", marginLeft: "0.25rem" }, children: "*" })
3355
- ]
3356
- }
3357
- ),
3358
- description && /* @__PURE__ */ jsx(
3359
- "div",
3360
- {
3361
- style: {
3362
- color: "#6b7280",
3363
- fontSize: "0.75rem",
3364
- marginBottom: "0.5rem"
3365
- },
3366
- children: description
3367
- }
3368
- ),
3426
+ label && /* @__PURE__ */ jsxs("label", { htmlFor: path2, className: fieldLabelClass(scaleName), children: [
3427
+ label,
3428
+ required && /* @__PURE__ */ jsx("span", { className: "ml-1 text-destructive", children: "*" })
3429
+ ] }),
3430
+ description && /* @__PURE__ */ jsx("div", { className: fieldHintClass, children: description }),
3369
3431
  /* @__PURE__ */ jsx(
3370
3432
  "textarea",
3371
3433
  {
3434
+ id: path2,
3372
3435
  ref: textareaRef,
3373
3436
  value: data || "",
3374
3437
  onChange: handleInputChange,
3375
3438
  placeholder,
3376
3439
  disabled: isDisabled,
3377
3440
  rows: minRows,
3441
+ className: `resize-y ${fieldControlClass(scaleName, !!hasError)}`,
3378
3442
  style: {
3379
- width: "100%",
3380
- minHeight: "80px",
3381
- maxHeight: "240px",
3382
- resize: "vertical",
3383
- padding: "0.75rem",
3384
- border: hasError ? "2px solid #ef4444" : "1px solid #d1d5db",
3385
- borderRadius: "6px",
3386
- fontSize: "16px",
3387
- lineHeight: "1.5",
3388
- fontFamily: "inherit",
3389
- backgroundColor: isDisabled ? "#f9fafb" : "#ffffff",
3390
- color: isDisabled ? "#9ca3af" : "#111827",
3391
- outline: "none",
3392
- transition: "border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out",
3393
- boxShadow: hasError ? "0 0 0 1px #ef4444" : "none",
3443
+ minHeight: `${minHeight}px`,
3444
+ maxHeight: `${ceiling}px`,
3445
+ // iOS zooms a focused control under 16px; the design's fields are
3446
+ // 14px, so opt out of the adjustment rather than the design.
3394
3447
  WebkitTextSizeAdjust: "100%"
3395
- },
3396
- onFocus: (e) => {
3397
- if (!hasError) {
3398
- e.target.style.borderColor = "#6366f1";
3399
- e.target.style.boxShadow = "0 0 0 1px #6366f1";
3400
- }
3401
- },
3402
- onBlur: (e) => {
3403
- if (!hasError) {
3404
- e.target.style.borderColor = "#d1d5db";
3405
- e.target.style.boxShadow = "none";
3406
- }
3407
3448
  }
3408
3449
  }
3409
3450
  ),
3410
- hasError && /* @__PURE__ */ jsx(
3411
- "div",
3412
- {
3413
- style: {
3414
- color: "#ef4444",
3415
- fontSize: "0.75rem",
3416
- marginTop: "0.25rem"
3417
- },
3418
- children: errors
3419
- }
3420
- )
3451
+ hasError && /* @__PURE__ */ jsx("div", { className: fieldErrorClass, children: errors })
3421
3452
  ] });
3422
3453
  };
3423
3454
  var textareaRendererTester = rankWith(
@@ -3469,10 +3500,25 @@ var renderers = [
3469
3500
  ];
3470
3501
 
3471
3502
  // src/chat-variables/VariablesForm.vm.ts
3503
+ var MAX_INLINE_VARIABLES = 3;
3504
+ var isModelSelector = (schema) => schema.title === "ModelId" || schema["x-model-selector"] === true;
3505
+ function rowLayout(controls) {
3506
+ const innerRow = {
3507
+ type: "HorizontalLayout",
3508
+ elements: controls,
3509
+ options: { gap: "12px", alignItems: "flex-start" }
3510
+ };
3511
+ const ui = {
3512
+ type: "VerticalLayout",
3513
+ elements: [innerRow]
3514
+ };
3515
+ return ui;
3516
+ }
3472
3517
  function buildSimpleSchemaAndUi(vars, threadVars, useDefaults) {
3473
3518
  const names = Object.keys(vars || {});
3474
3519
  const properties2 = {};
3475
3520
  const controls = [];
3521
+ const inlineOnly = [];
3476
3522
  const initialData = {};
3477
3523
  const $defs = {};
3478
3524
  for (const name of names) {
@@ -3492,19 +3538,24 @@ function buildSimpleSchemaAndUi(vars, threadVars, useDefaults) {
3492
3538
  control.enabled = false;
3493
3539
  }
3494
3540
  controls.push(control);
3541
+ if (isModelSelector(properties2[name])) inlineOnly.push(control);
3495
3542
  }
3496
3543
  const schema = { type: "object", properties: properties2 };
3497
3544
  if (Object.keys($defs).length > 0) schema.$defs = $defs;
3498
- const innerRow = {
3499
- type: "HorizontalLayout",
3500
- elements: controls,
3501
- options: { gap: "12px", alignItems: "flex-start" }
3502
- };
3503
- const ui = {
3504
- type: "VerticalLayout",
3505
- elements: [innerRow]
3545
+ if (controls.length <= MAX_INLINE_VARIABLES) {
3546
+ return {
3547
+ schema,
3548
+ inlineControls: controls,
3549
+ overflowControls: [],
3550
+ initialData
3551
+ };
3552
+ }
3553
+ return {
3554
+ schema,
3555
+ inlineControls: inlineOnly,
3556
+ overflowControls: controls.filter((c) => !inlineOnly.includes(c)),
3557
+ initialData
3506
3558
  };
3507
- return { schema, uiSchema: ui, initialData };
3508
3559
  }
3509
3560
  function useChatVariablesFormVm({
3510
3561
  workspace,
@@ -3519,26 +3570,26 @@ function useChatVariablesFormVm({
3519
3570
  const { mutate: updateVariableMutation } = useUpdateFlowRunVariable();
3520
3571
  const querySettled = !isLoading && (threadVars !== void 0 || isError);
3521
3572
  const shouldUseDefaults = isError || threadVars && Object.keys(threadVars).length === 0;
3522
- const built = React8.useMemo(() => {
3573
+ const built = React9.useMemo(() => {
3523
3574
  return buildSimpleSchemaAndUi(
3524
3575
  workspace.variables,
3525
3576
  threadVars,
3526
3577
  shouldUseDefaults ?? false
3527
3578
  );
3528
3579
  }, [workspace.variables, threadVars, shouldUseDefaults]);
3529
- const [data, setData] = React8.useState(null);
3530
- React8.useEffect(() => {
3580
+ const [data, setData] = React9.useState(null);
3581
+ React9.useEffect(() => {
3531
3582
  if (querySettled) {
3532
3583
  setData(built.initialData);
3533
3584
  setVariables(built.initialData);
3534
3585
  }
3535
3586
  }, [querySettled, built.initialData, setVariables]);
3536
- const ajv = React8.useMemo(() => createAjv({ useDefaults: false }), []);
3537
- const prevRef = React8.useRef(null);
3538
- React8.useEffect(() => {
3587
+ const ajv = React9.useMemo(() => createAjv({ useDefaults: false }), []);
3588
+ const prevRef = React9.useRef(null);
3589
+ React9.useEffect(() => {
3539
3590
  prevRef.current = data;
3540
3591
  }, [data]);
3541
- const onChange = React8.useCallback(
3592
+ const onChange = React9.useCallback(
3542
3593
  ({ data: next2 }) => {
3543
3594
  if (prevRef.current && !isDraftThreadId(threadId)) {
3544
3595
  const keys2 = Object.keys(workspace.variables || {});
@@ -3559,29 +3610,96 @@ function useChatVariablesFormVm({
3559
3610
  },
3560
3611
  [workspace.variables, setVariables, updateVariableMutation, threadId]
3561
3612
  );
3562
- const config = React8.useMemo(
3613
+ const barConfig = React9.useMemo(
3563
3614
  () => ({
3564
3615
  restrict: true,
3565
3616
  trim: false,
3566
3617
  showUnfocusedDescription: true,
3567
- hideRequiredAsterisk: true
3618
+ hideRequiredAsterisk: true,
3619
+ surface: "bar",
3620
+ minRows: 1,
3621
+ maxRows: 6
3568
3622
  }),
3569
3623
  []
3570
3624
  );
3625
+ const panelConfig = React9.useMemo(
3626
+ () => ({ ...barConfig, surface: "panel" }),
3627
+ [barConfig]
3628
+ );
3629
+ const inlineUiSchema = React9.useMemo(
3630
+ () => built.inlineControls.length ? rowLayout(built.inlineControls) : null,
3631
+ [built.inlineControls]
3632
+ );
3633
+ const overflowUiSchema = React9.useMemo(
3634
+ () => built.overflowControls.length ? rowLayout(built.overflowControls) : null,
3635
+ [built.overflowControls]
3636
+ );
3571
3637
  return {
3572
3638
  schema: built.schema,
3573
- uiSchema: built.uiSchema,
3639
+ inlineUiSchema,
3640
+ overflowUiSchema,
3641
+ overflowCount: built.overflowControls.length,
3574
3642
  data,
3575
3643
  renderers,
3576
3644
  cells,
3577
3645
  ajv,
3578
3646
  onChange,
3579
- config,
3647
+ barConfig,
3648
+ panelConfig,
3580
3649
  isLoading,
3581
3650
  isReady: querySettled,
3582
3651
  isHydrated: data !== null
3583
3652
  };
3584
3653
  }
3654
+ function VariablesOverflowPanel({ count, children: children2 }) {
3655
+ const triggerRef = useRef(null);
3656
+ const panelRef = useRef(null);
3657
+ const { isOpen, close, toggle, renderPopover } = useAnchoredPopover({
3658
+ trigger: triggerRef,
3659
+ popover: panelRef,
3660
+ width: POPOVER_WIDTH_PX,
3661
+ maxHeight: POPOVER_MAX_HEIGHT_PX,
3662
+ role: "dialog",
3663
+ label: "Workspace variables"
3664
+ });
3665
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3666
+ /* @__PURE__ */ jsxs(
3667
+ "button",
3668
+ {
3669
+ ref: triggerRef,
3670
+ type: "button",
3671
+ onClick: toggle,
3672
+ "aria-expanded": isOpen,
3673
+ "aria-haspopup": "dialog",
3674
+ "aria-label": `Variables (${count})`,
3675
+ className: `flex h-8 shrink-0 items-center gap-1.5 rounded-full border px-2.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${isOpen ? "border-primary/30 bg-primary/10 text-primary" : "border-border/70 bg-transparent text-muted-foreground hover:bg-secondary"}`,
3676
+ children: [
3677
+ /* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-3.5 w-3.5 shrink-0" }),
3678
+ /* @__PURE__ */ jsx("span", { className: "inline max-sm:hidden", children: "Variables" }),
3679
+ /* @__PURE__ */ jsx("span", { className: "rounded-full bg-secondary px-1.5 text-[10px] leading-4 tabular-nums", children: count })
3680
+ ]
3681
+ }
3682
+ ),
3683
+ renderPopover(
3684
+ /* @__PURE__ */ jsxs(Fragment, { children: [
3685
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between border-b border-border px-3 py-2", children: [
3686
+ /* @__PURE__ */ jsx("span", { className: popoverHeadingClass, children: "Variables" }),
3687
+ /* @__PURE__ */ jsx(
3688
+ "button",
3689
+ {
3690
+ type: "button",
3691
+ onClick: close,
3692
+ "aria-label": "Close variables",
3693
+ className: "inline-flex h-5 w-5 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground",
3694
+ children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
3695
+ }
3696
+ )
3697
+ ] }),
3698
+ /* @__PURE__ */ jsx("div", { className: "ss-variables-panel min-h-0 overflow-y-auto p-3", children: children2 })
3699
+ ] })
3700
+ )
3701
+ ] });
3702
+ }
3585
3703
  var ChatVariablesForm = forwardRef(({ workspace, threadId, setVariables }, ref) => {
3586
3704
  const vm = useChatVariablesFormVm({ workspace, threadId, setVariables });
3587
3705
  useImperativeHandle(ref, () => ({
@@ -3597,19 +3715,32 @@ var ChatVariablesForm = forwardRef(({ workspace, threadId, setVariables }, ref)
3597
3715
  if (!vm.isHydrated) {
3598
3716
  return /* @__PURE__ */ jsx("div", { className: "flex justify-center items-center w-full h-8", children: /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin text-primary" }) });
3599
3717
  }
3600
- return /* @__PURE__ */ jsx("div", { className: "w-full jsonforms-compact", children: /* @__PURE__ */ jsx(
3601
- JsonForms,
3602
- {
3603
- schema: vm.schema,
3604
- uischema: vm.uiSchema,
3605
- data: vm.data,
3606
- renderers: vm.renderers,
3607
- cells: vm.cells,
3608
- ajv: vm.ajv,
3609
- onChange: vm.onChange,
3610
- config: vm.config
3611
- }
3612
- ) });
3718
+ const formProps = {
3719
+ schema: vm.schema,
3720
+ data: vm.data,
3721
+ renderers: vm.renderers,
3722
+ cells: vm.cells,
3723
+ ajv: vm.ajv,
3724
+ onChange: vm.onChange
3725
+ };
3726
+ return /* @__PURE__ */ jsxs("div", { className: "flex w-full min-w-0 items-center gap-1", children: [
3727
+ vm.inlineUiSchema && /* @__PURE__ */ jsx("div", { className: "min-w-0 jsonforms-compact", children: /* @__PURE__ */ jsx(
3728
+ JsonForms,
3729
+ {
3730
+ ...formProps,
3731
+ uischema: vm.inlineUiSchema,
3732
+ config: vm.barConfig
3733
+ }
3734
+ ) }),
3735
+ vm.overflowUiSchema && /* @__PURE__ */ jsx(VariablesOverflowPanel, { count: vm.overflowCount, children: /* @__PURE__ */ jsx("div", { className: "jsonforms-compact", children: /* @__PURE__ */ jsx(
3736
+ JsonForms,
3737
+ {
3738
+ ...formProps,
3739
+ uischema: vm.overflowUiSchema,
3740
+ config: vm.panelConfig
3741
+ }
3742
+ ) }) })
3743
+ ] });
3613
3744
  });
3614
3745
 
3615
3746
  // src/domains/workspaces/queryKeys.ts
@@ -4081,7 +4212,7 @@ function MessageComposer(_props = {}) {
4081
4212
  disabled,
4082
4213
  placeholder: "What would you like to do?",
4083
4214
  className: "md-editor--bare px-5 pb-3 pt-4 text-sm",
4084
- minHeight: 48
4215
+ minHeight: 24
4085
4216
  },
4086
4217
  `composer-md-${editorKey}`
4087
4218
  ) }),
@@ -18944,6 +19075,79 @@ var getMessageErrorText = (error) => {
18944
19075
  }
18945
19076
  return STATUS_CODE_TEXT[error.code] ?? GENERIC_ERROR_TEXT;
18946
19077
  };
19078
+ var FileInfoSchema = z.object({
19079
+ id: z.string(),
19080
+ name: z.string()
19081
+ });
19082
+ z.object({
19083
+ workspaceId: z.string().optional(),
19084
+ threadId: z.string().optional()
19085
+ });
19086
+
19087
+ // src/domains/messages/schemas.ts
19088
+ var MessageResponseSourceSchema = z.object({
19089
+ index: z.number(),
19090
+ datasetItemId: z.string().optional(),
19091
+ containerItemId: z.string().nullish(),
19092
+ flowRunId: z.string().optional(),
19093
+ file: FileInfoSchema.nullish(),
19094
+ url: z.string().nullish(),
19095
+ sourceType: z.nativeEnum(MessageResponseSourceType),
19096
+ // WS3c citation grounding (additive; absent on older responses).
19097
+ uri: z.string().nullish(),
19098
+ citedText: z.string().nullish(),
19099
+ attribution: z.nativeEnum(MessageAttribution).nullish(),
19100
+ // Where the cited item lives at its source (SharePoint web link, HubSpot record page).
19101
+ // Distinct from `url` (the source *is* that URL): this rides File sources so the card
19102
+ // can offer "open at source" beside the download of our copy. Absent when unknown.
19103
+ webUrl: z.string().nullish()
19104
+ });
19105
+ var MessageResponseSchema = z.object({
19106
+ content: z.string(),
19107
+ messageId: z.string(),
19108
+ sources: z.array(MessageResponseSourceSchema).nullish(),
19109
+ isReplying: z.boolean().nullish().default(false),
19110
+ requestedJsonSchema: z.string().nullish()
19111
+ });
19112
+ var MessageErrorMessageSchema = z.object({
19113
+ code: z.number(),
19114
+ // Stable machine-readable category (e.g. "llm.rate_limit"). Accept both
19115
+ // spellings: app-api serialises camelCase, the ai-api origin field is
19116
+ // snake_case — the mapper coalesces them.
19117
+ errorCode: z.string().nullish(),
19118
+ error_code: z.string().nullish(),
19119
+ message: z.string().nullish(),
19120
+ data: z.string().nullish(),
19121
+ blockId: z.string().nullish()
19122
+ });
19123
+ var MessageSchema = z.object({
19124
+ id: z.string().nullish(),
19125
+ createdAt: DateFromApi,
19126
+ createdBy: z.string().nullish(),
19127
+ hasComments: z.boolean().default(false),
19128
+ createdByUserId: z.string().nullish(),
19129
+ messageThreadId: z.string().nullish(),
19130
+ errors: z.array(MessageErrorMessageSchema).nullish(),
19131
+ values: z.array(
19132
+ z.object({
19133
+ id: z.string(),
19134
+ name: z.string(),
19135
+ type: z.nativeEnum(MessageValueType),
19136
+ value: z.any(),
19137
+ // Can be string (for Output), array (for Input), or object (for Variables)
19138
+ channels: z.record(z.string(), z.number()),
19139
+ createdAt: DateFromApi,
19140
+ createdBy: z.string(),
19141
+ createdByUserId: z.string().nullish()
19142
+ })
19143
+ ).nullish(),
19144
+ optimistic: z.boolean().optional().default(false)
19145
+ });
19146
+ z.object({
19147
+ text: z.string().nullish(),
19148
+ image: FileInfoSchema.nullish()
19149
+ });
19150
+ z.array(MessageSchema);
18947
19151
 
18948
19152
  // src/domains/messages/statuses.ts
18949
19153
  var asRecord = (value) => {
@@ -19087,7 +19291,7 @@ var buttonVariants = cva(
19087
19291
  }
19088
19292
  }
19089
19293
  );
19090
- var Button = React8.forwardRef(
19294
+ var Button = React9.forwardRef(
19091
19295
  ({ className, variant, size, asChild = false, ...props }, ref) => {
19092
19296
  const Comp = asChild ? Slot : "button";
19093
19297
  return /* @__PURE__ */ jsx(
@@ -19638,6 +19842,7 @@ function ChatMessageSources({
19638
19842
  ] })
19639
19843
  ] });
19640
19844
  }
19845
+ var USER_FORM_CONFIG = { surface: "form", minRows: 6, maxRows: 20 };
19641
19846
  var REVEAL_ON_HOVER = "opacity-100 focus-visible:opacity-100 [@media(hover:hover)]:opacity-0 [@media(hover:hover)]:group-hover:opacity-100";
19642
19847
  var MessageBubble = (props) => {
19643
19848
  const {
@@ -19691,7 +19896,7 @@ var MessageBubble = (props) => {
19691
19896
  );
19692
19897
  })
19693
19898
  ] }),
19694
- showForm && /* @__PURE__ */ jsxs("div", { className: "mt-4 border-t border-border pt-4", children: [
19899
+ showForm && /* @__PURE__ */ jsxs("div", { className: "ss-chat-message__user-form mt-4 border-t border-border pt-4", children: [
19695
19900
  /* @__PURE__ */ jsx(
19696
19901
  JsonForms,
19697
19902
  {
@@ -19700,6 +19905,7 @@ var MessageBubble = (props) => {
19700
19905
  renderers,
19701
19906
  cells,
19702
19907
  readonly: userInput !== void 0,
19908
+ config: USER_FORM_CONFIG,
19703
19909
  onChange: ({ data, errors }) => {
19704
19910
  setResponseFormData(data);
19705
19911
  setResponseFormValid(!errors?.length);
@@ -19832,6 +20038,10 @@ function coerceSources(x) {
19832
20038
  if (!Array.isArray(x)) return [];
19833
20039
  return x.filter(isMessageResponseSource);
19834
20040
  }
20041
+ var ENVELOPE_KEYS = Object.keys(MessageResponseSchema.shape);
20042
+ function isResponseEnvelope(keys2) {
20043
+ return keys2.length > 0 && keys2.every((key) => ENVELOPE_KEYS.includes(key));
20044
+ }
19835
20045
  var MessageItem = ({
19836
20046
  message,
19837
20047
  isLive = false
@@ -19840,14 +20050,14 @@ var MessageItem = ({
19840
20050
  const { data: workspace } = useWorkspace(workspaceId);
19841
20051
  const chatbotName = getChatbotName(workspace?.name);
19842
20052
  const { addInputToMessageMutation } = useAddInputToMessage();
19843
- const onSubmitUserForm = (messageId) => (name, value) => {
20053
+ const onSubmitUserForm = (messageId, channels = {}) => (name, value) => {
19844
20054
  if (!threadId || !messageId) return;
19845
20055
  addInputToMessageMutation.mutate({
19846
20056
  threadId,
19847
20057
  messageId,
19848
20058
  name,
19849
20059
  value,
19850
- channels: {}
20060
+ channels
19851
20061
  });
19852
20062
  };
19853
20063
  const safeTime = (d) => {
@@ -19939,9 +20149,16 @@ var MessageItem = ({
19939
20149
  });
19940
20150
  } else if (name === "response" && typeof v.value === "object" && v.value !== null && !Array.isArray(v.value)) {
19941
20151
  const resp = v.value;
19942
- const isContentPart = "text" in resp || "image" in resp;
19943
- pushContent(groupContent, isContentPart ? resp : resp.content);
19944
- groupSources = coerceSources(resp.sources);
20152
+ const keys2 = Object.keys(resp);
20153
+ const isEnvelope = isResponseEnvelope(keys2);
20154
+ if ("sources" in resp && (isEnvelope || "text" in resp || "image" in resp)) {
20155
+ groupSources = coerceSources(resp.sources);
20156
+ }
20157
+ if (isEnvelope) {
20158
+ pushContent(groupContent, resp.content);
20159
+ } else if (keys2.length > 0) {
20160
+ pushContent(groupContent, resp);
20161
+ }
19945
20162
  } else {
19946
20163
  pushContent(groupContent, v.value);
19947
20164
  }
@@ -19971,7 +20188,7 @@ var MessageItem = ({
19971
20188
  userOutput: v.value && typeof v.value === "object" ? v.value : null,
19972
20189
  chatbotName,
19973
20190
  userInput: userInput?.value,
19974
- onSubmitUserForm: onSubmitUserForm(message.id ?? "")
20191
+ onSubmitUserForm: onSubmitUserForm(message.id ?? "", v.channels)
19975
20192
  },
19976
20193
  `user-${message.id ?? "msg"}-${keyCounter++}`
19977
20194
  )
@@ -20167,6 +20384,7 @@ function MessageList({
20167
20384
  ] }) });
20168
20385
  }
20169
20386
  if (safeMessages.length === 0 && !hadMessagesBefore) {
20387
+ const descriptionParagraphs = (activeWorkspace?.summary ?? "").split(/\n+/).map((paragraph2) => paragraph2.trim()).filter(Boolean);
20170
20388
  return (
20171
20389
  // A new thread opens the way the design does: the greeting and the
20172
20390
  // composer travel together as one narrower block centred in the canvas.
@@ -20179,6 +20397,14 @@ function MessageList({
20179
20397
  "data-ss-layer": "message-list",
20180
20398
  children: /* @__PURE__ */ jsxs("div", { className: "mx-auto mb-6 w-full max-w-2xl px-4 text-center", children: [
20181
20399
  /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold text-foreground", children: "What\u2019s on the agenda today?" }),
20400
+ descriptionParagraphs.length > 0 && /* @__PURE__ */ jsx(
20401
+ "div",
20402
+ {
20403
+ className: "mx-auto mt-2 max-w-lg space-y-1.5 text-sm text-muted-foreground",
20404
+ "data-ss-layer": "workspace-description",
20405
+ children: descriptionParagraphs.map((paragraph2, index) => /* @__PURE__ */ jsx("p", { children: paragraph2 }, index))
20406
+ }
20407
+ ),
20182
20408
  activeWorkspace?.firstPrompt && /* @__PURE__ */ jsx("div", { className: "chat-prose mt-3 text-center", children: /* @__PURE__ */ jsx(MessageMarkdown, { value: activeWorkspace.firstPrompt }) })
20183
20409
  ] })
20184
20410
  }