@iloveagents/foundry-web-ui 0.30.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/assistant-chat.js +1 -1
- package/dist/components/markdown-text.js +6 -4
- package/dist/components/sidebar.js +12 -7
- package/dist/components/tool-panel.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/lib/auth-provider.js +1 -1
- package/dist/lib/theme-runtime.d.ts +23 -0
- package/dist/lib/theme-runtime.js +210 -30
- package/dist/lib/theme-store.d.ts +3 -1
- package/dist/lib/theme-store.js +3 -2
- package/dist/styles.css +14 -0
- package/dist/workbench/selection-bridge.js +2 -5
- package/dist/workbench/workbench-styles.js +0 -1
- package/package.json +3 -3
|
@@ -137,7 +137,7 @@ export function ChatContent({ centerComposer = false, composerIntro, composerFoo
|
|
|
137
137
|
// `overflow-hidden`, not scroll: a surface owns its own layout,
|
|
138
138
|
// and a full-bleed one (an avatar cropped to the frame) must be
|
|
139
139
|
// able to reach the edges rather than sit in a scroll box.
|
|
140
|
-
_jsx("div", { className: "absolute inset-0 z-10 overflow-hidden bg-background", children: _jsx(ThreadSurface, {}) })), _jsxs(ThreadPrimitive.Viewport, { className: cn("absolute inset-0 overflow-y-auto bg-background", ThreadSurface && "invisible"), "aria-hidden": ThreadSurface ? true : undefined, children: [_jsx(ThreadPrimitive.Empty, { children: emptyState ?? (_jsxs("div", { className: cn("flex min-h-full flex-col", "items-center justify-center", "px-4"), children: [_jsx(Bot, { className: "size-16 mb-6 text-primary/70" }), _jsx("h1", { className: "text-[2rem] font-normal text-
|
|
140
|
+
_jsx("div", { className: "absolute inset-0 z-10 overflow-hidden bg-background", children: _jsx(ThreadSurface, {}) })), _jsxs(ThreadPrimitive.Viewport, { className: cn("absolute inset-0 overflow-y-auto bg-background", ThreadSurface && "invisible"), "aria-hidden": ThreadSurface ? true : undefined, children: [_jsx(ThreadPrimitive.Empty, { children: emptyState ?? (_jsxs("div", { className: cn("flex min-h-full flex-col", "items-center justify-center", "px-4"), children: [_jsx(Bot, { className: "size-16 mb-6 text-primary/70" }), _jsx("h1", { className: "text-[2rem] font-normal text-heading text-center mb-6", children: "How can I help you today?" }), _jsx(ChatHomeStartersSlot, {}), starterSuggestions.length > 0 && (_jsx("div", { className: "flex flex-wrap justify-center gap-2 max-w-lg", children: starterSuggestions.map((prompt) => (_jsx(ThreadPrimitive.Suggestion, { prompt: prompt, send: true, asChild: true, children: _jsx(Button, { variant: "outline", className: "text-sm", children: prompt }) }, prompt))) }))] })) }), _jsx(ThreadPrimitive.If, { empty: false, children: _jsxs("div", { className: "mx-auto max-w-3xl px-4 pt-8 pb-4", children: [_jsx(ThreadPrimitive.Messages, { components: {
|
|
141
141
|
UserMessage,
|
|
142
142
|
EditComposer,
|
|
143
143
|
AssistantMessage,
|
|
@@ -132,10 +132,12 @@ function extractCodeInfo(children) {
|
|
|
132
132
|
* Shared markdown component overrides used by both chat messages and the tool panel.
|
|
133
133
|
*/
|
|
134
134
|
export const markdownComponents = {
|
|
135
|
-
h1: ({ children, ...props }) => (_jsx("h1", { className: "text-2xl font-bold mt-6 mb-4 text-
|
|
136
|
-
h2: ({ children, ...props }) => (_jsx("h2", { className: "text-xl font-bold mt-5 mb-3 text-
|
|
137
|
-
h3: ({ children, ...props }) => (_jsx("h3", { className: "text-lg font-semibold mt-4 mb-2 text-
|
|
138
|
-
h4: ({ children, ...props }) => (_jsx("h4", { className: "text-base font-semibold mt-3 mb-1.5 text-
|
|
135
|
+
h1: ({ children, ...props }) => (_jsx("h1", { className: "text-2xl font-bold mt-6 mb-4 text-content-heading-1", ...props, children: children })),
|
|
136
|
+
h2: ({ children, ...props }) => (_jsx("h2", { className: "text-xl font-bold mt-5 mb-3 text-content-heading-2", ...props, children: children })),
|
|
137
|
+
h3: ({ children, ...props }) => (_jsx("h3", { className: "text-lg font-semibold mt-4 mb-2 text-content-heading-3", ...props, children: children })),
|
|
138
|
+
h4: ({ children, ...props }) => (_jsx("h4", { className: "text-base font-semibold mt-3 mb-1.5 text-content-heading-4", ...props, children: children })),
|
|
139
|
+
h5: ({ children, ...props }) => (_jsx("h5", { className: "mt-3 mb-1.5 text-sm font-semibold text-content-heading-5", ...props, children: children })),
|
|
140
|
+
h6: ({ children, ...props }) => (_jsx("h6", { className: "mt-3 mb-1.5 text-xs font-semibold text-content-heading-6", ...props, children: children })),
|
|
139
141
|
p: ({ children, ...props }) => (_jsx("p", { className: "mb-2 leading-relaxed text-foreground", ...props, children: injectCitations(children) })),
|
|
140
142
|
ul: ({ children, ...props }) => (_jsx("ul", { className: "list-disc list-outside pl-6 mb-4 space-y-1 text-foreground", ...props, children: children })),
|
|
141
143
|
ol: ({ children, ...props }) => (_jsx("ol", { className: "list-decimal list-outside pl-6 mb-4 space-y-1 text-foreground", ...props, children: children })),
|
|
@@ -13,9 +13,9 @@ import { TooltipIconButton } from "./tooltip-icon-button.js";
|
|
|
13
13
|
import { Button } from "@iloveagents/foundry-web-primitives";
|
|
14
14
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "../ui/dropdown-menu.js";
|
|
15
15
|
import { AppBrand } from "./app-brand.js";
|
|
16
|
-
const ACTIVE_NAV_ROW_CLASS = "border border-transparent bg-sidebar-selected shadow-none";
|
|
17
|
-
const ACTIVE_NAV_TEXT_CLASS = "font-semibold text-sidebar-foreground";
|
|
18
|
-
const ACTIVE_NAV_ICON_CLASS = "text-
|
|
16
|
+
const ACTIVE_NAV_ROW_CLASS = "border border-transparent bg-sidebar-selected text-sidebar-selected-foreground shadow-none";
|
|
17
|
+
const ACTIVE_NAV_TEXT_CLASS = "font-semibold text-sidebar-selected-foreground";
|
|
18
|
+
const ACTIVE_NAV_ICON_CLASS = "text-sidebar-selected-foreground";
|
|
19
19
|
const ACTIVE_NAV_BADGE_CLASS = "border border-sidebar-border bg-background/60 text-sidebar-foreground";
|
|
20
20
|
// Indent ladder for the nav tree, indexed by depth (0 = top-level item).
|
|
21
21
|
//
|
|
@@ -437,13 +437,15 @@ function ContainerDropZone({ dnd }) {
|
|
|
437
437
|
function NavTwisty({ hasChildren, childrenUnloaded = false, isExpanded, onToggle, label, isActive, depth, inTree = true, }) {
|
|
438
438
|
const cell = cn(NAV_TWISTY_CLASS, getNavDepthOffsets(depth).column);
|
|
439
439
|
if (!hasChildren) {
|
|
440
|
-
return (_jsx("span", { "data-nav-twisty-cell": true, "aria-hidden": "true", className: cn(cell, "pointer-events-none"), children: inTree && !childrenUnloaded && (_jsx("span", { "data-nav-leaf-dot": true, className: cn("block size-1 shrink-0 rounded-full", isActive ? "bg-
|
|
440
|
+
return (_jsx("span", { "data-nav-twisty-cell": true, "aria-hidden": "true", className: cn(cell, "pointer-events-none"), children: inTree && !childrenUnloaded && (_jsx("span", { "data-nav-leaf-dot": true, className: cn("block size-1 shrink-0 rounded-full", isActive ? "bg-sidebar-selected-foreground/70" : "bg-sidebar-foreground/30") })) }));
|
|
441
441
|
}
|
|
442
442
|
return (_jsx("span", { "data-nav-twisty-cell": true, className: cell, children: _jsx("button", { type: "button", "data-nav-twisty": true, "aria-expanded": isExpanded, "aria-label": isExpanded ? `Collapse ${label}` : `Expand ${label}`, onClick: (e) => {
|
|
443
443
|
e.preventDefault();
|
|
444
444
|
e.stopPropagation();
|
|
445
445
|
onToggle?.();
|
|
446
|
-
}, className: cn("flex items-center justify-center rounded", NAV_TWISTY_HIT_CLASS, isActive
|
|
446
|
+
}, className: cn("flex items-center justify-center rounded", NAV_TWISTY_HIT_CLASS, isActive
|
|
447
|
+
? "text-sidebar-selected-foreground"
|
|
448
|
+
: "text-sidebar-foreground/50 hover:text-sidebar-foreground"), children: _jsx(ChevronRight, { className: cn("size-3.5 transition-transform duration-150", isExpanded && "rotate-90") }) }) }));
|
|
447
449
|
}
|
|
448
450
|
function NavItemActions({ actions }) {
|
|
449
451
|
return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "size-7 rounded-md text-muted-foreground hover:bg-muted/80 hover:text-foreground", onClick: (e) => {
|
|
@@ -666,7 +668,9 @@ function CollapsibleNavItem({ item, inTree = true, heading = false, underHeader
|
|
|
666
668
|
: heading || !underHeader
|
|
667
669
|
? NAV_FLAT_BODY_CLASS
|
|
668
670
|
: getNavDepthOffsets(0).body;
|
|
669
|
-
const headingClass = heading &&
|
|
671
|
+
const headingClass = heading &&
|
|
672
|
+
!isDisabled &&
|
|
673
|
+
`font-semibold ${isActive ? "text-sidebar-selected-foreground" : "text-sidebar-primary"}`;
|
|
670
674
|
const { draggableProps, dropTargetProps, isDragOver, isFileDragOver } = useNavItemDnd(item.dnd);
|
|
671
675
|
const rendersRow = Boolean(hasChildren || hasActions);
|
|
672
676
|
const activeRowRef = useActiveNavRowScroll(isActive && rendersRow);
|
|
@@ -794,7 +798,8 @@ function SidebarResizeHandle() {
|
|
|
794
798
|
// group is now the source of truth for "you're in a chat right now".
|
|
795
799
|
// Kept as a comment so future spelunkers know it was intentional.
|
|
796
800
|
function CollapsedNavShortcut({ to, label, icon: Icon, isActive, }) {
|
|
797
|
-
return (_jsx(NavLink, { to: to, children: _jsx(TooltipIconButton, { tooltip: label, side: "right", className: cn(isActive &&
|
|
801
|
+
return (_jsx(NavLink, { to: to, children: _jsx(TooltipIconButton, { tooltip: label, side: "right", className: cn(isActive &&
|
|
802
|
+
"border border-transparent bg-sidebar-selected text-sidebar-selected-foreground"), children: _jsx(Icon, { className: cn("size-4", isActive ? "text-sidebar-selected-foreground" : "text-sidebar-icon") }) }) }, to));
|
|
798
803
|
}
|
|
799
804
|
// ---------------------------------------------------------------------------
|
|
800
805
|
// Collapsible nav-group state — persisted per-label in localStorage so the
|
|
@@ -141,5 +141,5 @@ export function ToolPanel({ contained = false }) {
|
|
|
141
141
|
else
|
|
142
142
|
return;
|
|
143
143
|
event.preventDefault();
|
|
144
|
-
}, className: cn("absolute left-0 top-0 z-10 h-full w-2 -translate-x-1/2", "cursor-col-resize touch-none", "before:absolute before:inset-y-0 before:left-1/2 before:w-px before:-translate-x-1/2", "before:bg-transparent hover:before:bg-primary/40 focus-visible:before:bg-primary", "focus:outline-none") })) : null, _jsx("div", { className: "flex-shrink-0 border-b border-border px-6 py-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-lg font-semibold text-
|
|
144
|
+
}, className: cn("absolute left-0 top-0 z-10 h-full w-2 -translate-x-1/2", "cursor-col-resize touch-none", "before:absolute before:inset-y-0 before:left-1/2 before:w-px before:-translate-x-1/2", "before:bg-transparent hover:before:bg-primary/40 focus-visible:before:bg-primary", "focus:outline-none") })) : null, _jsx("div", { className: "flex-shrink-0 border-b border-border px-6 py-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-lg font-semibold text-heading truncate pr-4", children: content.title }), _jsxs("div", { className: "flex items-center gap-1", children: [entityId && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: handleToggleEntityPin, className: cn("flex items-center justify-center", "size-8 rounded-md shrink-0", "hover:bg-muted transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary", isEntityPinned ? "text-foreground" : "text-muted-foreground"), "aria-pressed": isEntityPinned, "aria-label": isEntityPinned ? "Unpin document" : "Pin document", title: isEntityPinned ? "Unpin document" : "Pin document", children: _jsx(PinStateIcon, { pinned: isEntityPinned }) }), _jsx("button", { type: "button", onClick: handleNavigateToEntity, className: cn("flex items-center justify-center", "size-8 rounded-md shrink-0", "hover:bg-muted transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"), "aria-label": "Open in navigation", title: "Open in navigation", children: _jsx(FolderOpen, { className: "size-4 text-muted-foreground" }) })] })), _jsx("button", { type: "button", onClick: handleCopyAll, className: cn("flex items-center justify-center", "size-8 rounded-md flex-shrink-0", "hover:bg-muted transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"), "aria-label": "Copy content", children: copied ? (_jsx(Check, { className: "size-4 text-success" })) : (_jsx(Copy, { className: "size-4 text-muted-foreground" })) }), !contained && (_jsx("button", { type: "button", onClick: toggleFullscreen, className: cn("flex items-center justify-center", "size-8 rounded-md flex-shrink-0", "hover:bg-muted transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"), "aria-label": isFullscreen ? "Exit fullscreen" : "Fullscreen", children: isFullscreen ? (_jsx(Minimize2, { className: "size-4 text-muted-foreground" })) : (_jsx(Maximize2, { className: "size-4 text-muted-foreground" })) })), _jsx("button", { type: "button", onClick: closePanel, className: cn("flex items-center justify-center", "size-8 rounded-md flex-shrink-0", "hover:bg-muted transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"), "aria-label": "Close panel", children: _jsx(X, { className: "size-5 text-muted-foreground" }) })] })] }) }), _jsxs("div", { className: "relative flex-1 overflow-y-auto", ref: contentRef, "data-testid": "tool-panel-content", children: [_jsx(PanelContentRenderer, { content: content }), _jsx(SelectionPopover, { containerRef: contentRef })] })] }));
|
|
145
145
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -76,8 +76,8 @@ export { submitComposerText } from "./lib/composer-submit-store.js";
|
|
|
76
76
|
export { registerSelectionContextResolver, resolveSelectionContext, type SelectionContextInput, type SelectionContextItem, type SelectionContextResolver, type SelectionContextResult, } from "./lib/selection-context.js";
|
|
77
77
|
export { useThemeStore } from "./lib/theme-store.js";
|
|
78
78
|
export type { ThemeMode } from "./lib/theme-store.js";
|
|
79
|
-
export { mergeThemeDefinitions, resolveThemeRuntime, getEffectiveThemeMode, getThemePreset, } from "./lib/theme-runtime.js";
|
|
80
|
-
export type { ThemeDefinition, ThemeLayer, ResolvedThemeRuntime, ThemeColorSlots, ThemeSidebarSlots, ThemeStatusSlots, ThemeChartSlots, ThemeTypographySlots, ThemeRadiusSlots, ThemeAppSlots, ThemeBranding, } from "./lib/theme-runtime.js";
|
|
79
|
+
export { THEME_SLOTS, mergeThemeDefinitions, resolveThemeRuntime, getEffectiveThemeMode, getThemePreset, } from "./lib/theme-runtime.js";
|
|
80
|
+
export type { ThemeSlot, ThemeDefinition, ThemeLayer, ResolvedThemeRuntime, ThemeColorSlots, ThemeSidebarSlots, ThemeStatusSlots, ThemeChartSlots, ThemeTypographySlots, ThemeRadiusSlots, ThemeAppSlots, ThemeBranding, } from "./lib/theme-runtime.js";
|
|
81
81
|
export { useDevStore } from "./lib/dev-store.js";
|
|
82
82
|
export { DEFAULT_NAV_CONFIG, findNavItem } from "./lib/nav-config.js";
|
|
83
83
|
export type { NavItem, NavItemAction, NavItemDnd, NavGroup, NavGroupCreateAction, NavMatch, CollapsedRailItem, CollapsedRailContext, } from "./lib/nav-config.js";
|
package/dist/index.js
CHANGED
|
@@ -79,7 +79,7 @@ export { useChatLifecycleStore } from "./lib/chat-lifecycle-store.js";
|
|
|
79
79
|
export { submitComposerText } from "./lib/composer-submit-store.js";
|
|
80
80
|
export { registerSelectionContextResolver, resolveSelectionContext, } from "./lib/selection-context.js";
|
|
81
81
|
export { useThemeStore } from "./lib/theme-store.js";
|
|
82
|
-
export { mergeThemeDefinitions, resolveThemeRuntime, getEffectiveThemeMode, getThemePreset, } from "./lib/theme-runtime.js";
|
|
82
|
+
export { THEME_SLOTS, mergeThemeDefinitions, resolveThemeRuntime, getEffectiveThemeMode, getThemePreset, } from "./lib/theme-runtime.js";
|
|
83
83
|
// Stores moved to @iloveagents/foundry-agent (#95): authStore, citationStore,
|
|
84
84
|
// streamingStatusStore, clientToolRegistry. Consumers import directly from
|
|
85
85
|
// `@iloveagents/foundry-agent` / `@iloveagents/foundry-agent/msal` — no re-exports here per
|
|
@@ -42,7 +42,7 @@ export const AuthProvider = ({ config, children }) => {
|
|
|
42
42
|
if (!ready)
|
|
43
43
|
return null;
|
|
44
44
|
if (initError) {
|
|
45
|
-
return (_jsx("div", { className: "flex min-h-dvh items-center justify-center bg-background px-6 text-center", children: _jsxs("div", { className: "max-w-md rounded-2xl border border-border bg-card px-6 py-5 shadow-sm", children: [_jsx("h1", { className: "text-lg font-semibold text-
|
|
45
|
+
return (_jsx("div", { className: "flex min-h-dvh items-center justify-center bg-background px-6 text-center", children: _jsxs("div", { className: "max-w-md rounded-2xl border border-border bg-card px-6 py-5 shadow-sm", children: [_jsx("h1", { className: "text-lg font-semibold text-heading", children: "Authentication unavailable" }), _jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: initError })] }) }));
|
|
46
46
|
}
|
|
47
47
|
if (!MsalProvider || !useMsalHook) {
|
|
48
48
|
return null;
|
|
@@ -3,6 +3,15 @@ import type { ThemeMode } from "./theme-store.js";
|
|
|
3
3
|
export interface ThemeColorSlots {
|
|
4
4
|
background?: string;
|
|
5
5
|
foreground?: string;
|
|
6
|
+
/** Page and document headings, independent of body text and action colours. */
|
|
7
|
+
heading?: string;
|
|
8
|
+
/** Heading colours inside authored content, independent of application chrome. */
|
|
9
|
+
contentHeading1?: string;
|
|
10
|
+
contentHeading2?: string;
|
|
11
|
+
contentHeading3?: string;
|
|
12
|
+
contentHeading4?: string;
|
|
13
|
+
contentHeading5?: string;
|
|
14
|
+
contentHeading6?: string;
|
|
6
15
|
card?: string;
|
|
7
16
|
cardForeground?: string;
|
|
8
17
|
popover?: string;
|
|
@@ -161,6 +170,20 @@ export interface ResolvedThemeRuntime {
|
|
|
161
170
|
variables: CSSProperties;
|
|
162
171
|
sources: ThemeLayer[];
|
|
163
172
|
}
|
|
173
|
+
export interface ThemeSlot {
|
|
174
|
+
path: readonly string[];
|
|
175
|
+
label: string;
|
|
176
|
+
group: string;
|
|
177
|
+
kind: "color" | "font" | "length" | "text" | "image";
|
|
178
|
+
cssVariable?: string;
|
|
179
|
+
mode?: "light" | "dark";
|
|
180
|
+
/** Lower values appear first in authoring tools. */
|
|
181
|
+
impact: number;
|
|
182
|
+
/** Human-readable source used when this value is not explicitly set. */
|
|
183
|
+
derivedFrom?: string;
|
|
184
|
+
}
|
|
185
|
+
/** The same allowlists power sanitization and authoring: supported slots cannot disappear from editors. */
|
|
186
|
+
export declare const THEME_SLOTS: readonly ThemeSlot[];
|
|
164
187
|
export declare function mergeThemeDefinitions(...definitions: (ThemeDefinition | null | undefined)[]): ThemeDefinition;
|
|
165
188
|
export declare function getEffectiveThemeMode(mode: ThemeMode): "light" | "dark";
|
|
166
189
|
export declare const FOUNDRY_VIOLET_THEME: ThemeDefinition;
|
|
@@ -1,34 +1,41 @@
|
|
|
1
1
|
const COLOR_KEYS = [
|
|
2
|
+
"primary",
|
|
3
|
+
"primaryForeground",
|
|
4
|
+
"heading",
|
|
5
|
+
"contentHeading1",
|
|
6
|
+
"contentHeading2",
|
|
7
|
+
"contentHeading3",
|
|
8
|
+
"contentHeading4",
|
|
9
|
+
"contentHeading5",
|
|
10
|
+
"contentHeading6",
|
|
2
11
|
"background",
|
|
3
12
|
"foreground",
|
|
13
|
+
"accent",
|
|
14
|
+
"accentForeground",
|
|
4
15
|
"card",
|
|
5
16
|
"cardForeground",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"primaryForeground",
|
|
10
|
-
"secondary",
|
|
11
|
-
"secondaryForeground",
|
|
17
|
+
"border",
|
|
18
|
+
"ring",
|
|
19
|
+
"input",
|
|
12
20
|
"muted",
|
|
13
21
|
"mutedForeground",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
22
|
+
"secondary",
|
|
23
|
+
"secondaryForeground",
|
|
24
|
+
"popover",
|
|
25
|
+
"popoverForeground",
|
|
16
26
|
"destructive",
|
|
17
27
|
"destructiveForeground",
|
|
18
|
-
"border",
|
|
19
|
-
"input",
|
|
20
|
-
"ring",
|
|
21
28
|
];
|
|
22
29
|
const SIDEBAR_KEYS = [
|
|
30
|
+
"sidebarSelected",
|
|
31
|
+
"sidebarSelectedForeground",
|
|
23
32
|
"sidebar",
|
|
24
33
|
"sidebarForeground",
|
|
25
34
|
"sidebarPrimary",
|
|
26
35
|
"sidebarPrimaryForeground",
|
|
36
|
+
"sidebarIcon",
|
|
27
37
|
"sidebarAccent",
|
|
28
38
|
"sidebarAccentForeground",
|
|
29
|
-
"sidebarSelected",
|
|
30
|
-
"sidebarSelectedForeground",
|
|
31
|
-
"sidebarIcon",
|
|
32
39
|
"sidebarBorder",
|
|
33
40
|
"sidebarRing",
|
|
34
41
|
];
|
|
@@ -87,6 +94,100 @@ const BRANDING_KEYS = [
|
|
|
87
94
|
"darkIconUrl",
|
|
88
95
|
"logoHeight",
|
|
89
96
|
];
|
|
97
|
+
const SURFACE_IMPACT = Object.fromEntries(COLOR_KEYS.map((key, index) => [key, index]));
|
|
98
|
+
const SURFACE_DERIVATIONS = {
|
|
99
|
+
heading: "foreground",
|
|
100
|
+
contentHeading1: "interface heading",
|
|
101
|
+
contentHeading2: "interface heading + foreground",
|
|
102
|
+
contentHeading3: "foreground",
|
|
103
|
+
contentHeading4: "foreground",
|
|
104
|
+
contentHeading5: "foreground",
|
|
105
|
+
contentHeading6: "foreground",
|
|
106
|
+
card: "background",
|
|
107
|
+
cardForeground: "foreground",
|
|
108
|
+
popover: "card",
|
|
109
|
+
popoverForeground: "foreground",
|
|
110
|
+
secondary: "background + primary",
|
|
111
|
+
secondaryForeground: "foreground",
|
|
112
|
+
muted: "background + foreground",
|
|
113
|
+
mutedForeground: "foreground + background",
|
|
114
|
+
accent: "background + primary",
|
|
115
|
+
accentForeground: "foreground",
|
|
116
|
+
border: "foreground + background",
|
|
117
|
+
input: "border",
|
|
118
|
+
ring: "primary",
|
|
119
|
+
};
|
|
120
|
+
const cssName = (key) => `--${key.replace(/[A-Z0-9]/g, (part) => `-${part.toLowerCase()}`)}`;
|
|
121
|
+
const slotLabel = (key) => ({
|
|
122
|
+
heading: "Interface headings",
|
|
123
|
+
contentHeading1: "H1",
|
|
124
|
+
contentHeading2: "H2",
|
|
125
|
+
contentHeading3: "H3",
|
|
126
|
+
contentHeading4: "H4",
|
|
127
|
+
contentHeading5: "H5",
|
|
128
|
+
contentHeading6: "H6",
|
|
129
|
+
sidebarSelected: "Selected background",
|
|
130
|
+
sidebarSelectedForeground: "Selected text",
|
|
131
|
+
})[key] ?? key.replace(/([a-z])([A-Z0-9])/g, "$1 $2").replace(/^./, (c) => c.toUpperCase());
|
|
132
|
+
/** The same allowlists power sanitization and authoring: supported slots cannot disappear from editors. */
|
|
133
|
+
export const THEME_SLOTS = [
|
|
134
|
+
...["light", "dark"].flatMap((mode) => [
|
|
135
|
+
...COLOR_KEYS.map((key) => ({
|
|
136
|
+
path: [mode, key],
|
|
137
|
+
label: slotLabel(key),
|
|
138
|
+
group: key.startsWith("contentHeading") ? "Content" : "Surfaces",
|
|
139
|
+
kind: "color",
|
|
140
|
+
cssVariable: cssName(key),
|
|
141
|
+
mode,
|
|
142
|
+
impact: SURFACE_IMPACT[key],
|
|
143
|
+
derivedFrom: SURFACE_DERIVATIONS[key],
|
|
144
|
+
})),
|
|
145
|
+
...[
|
|
146
|
+
["sidebar", SIDEBAR_KEYS, "Navigation"],
|
|
147
|
+
["status", STATUS_KEYS, "Signals"],
|
|
148
|
+
["charts", CHART_KEYS, "Charts"],
|
|
149
|
+
["app", APP_KEYS, "Code & workflows"],
|
|
150
|
+
].flatMap(([section, keys, group]) => keys.map((key, impact) => ({
|
|
151
|
+
path: [section, mode, key],
|
|
152
|
+
label: slotLabel(key),
|
|
153
|
+
group,
|
|
154
|
+
kind: "color",
|
|
155
|
+
cssVariable: cssName(key),
|
|
156
|
+
mode,
|
|
157
|
+
impact,
|
|
158
|
+
derivedFrom: group === "Navigation"
|
|
159
|
+
? "page colours"
|
|
160
|
+
: group === "Signals" && String(key).startsWith("info")
|
|
161
|
+
? "primary action"
|
|
162
|
+
: group === "Code & workflows"
|
|
163
|
+
? "page and signal colours"
|
|
164
|
+
: undefined,
|
|
165
|
+
}))),
|
|
166
|
+
]),
|
|
167
|
+
...TYPOGRAPHY_KEYS.map((key) => ({
|
|
168
|
+
path: ["typography", key],
|
|
169
|
+
label: slotLabel(key),
|
|
170
|
+
group: "Typography & shape",
|
|
171
|
+
kind: "font",
|
|
172
|
+
cssVariable: `--font-${key.replace("Font", "")}`,
|
|
173
|
+
impact: key === "headingFont" ? 0 : key === "bodyFont" ? 1 : 3,
|
|
174
|
+
})),
|
|
175
|
+
...RADIUS_KEYS.map((key) => ({
|
|
176
|
+
path: ["radius", key],
|
|
177
|
+
label: "Corner radius",
|
|
178
|
+
group: "Typography & shape",
|
|
179
|
+
kind: "length",
|
|
180
|
+
cssVariable: cssName(key),
|
|
181
|
+
impact: 2,
|
|
182
|
+
})),
|
|
183
|
+
...BRANDING_KEYS.map((key) => ({
|
|
184
|
+
path: ["branding", key],
|
|
185
|
+
label: slotLabel(key),
|
|
186
|
+
group: "Brand",
|
|
187
|
+
kind: key.endsWith("Url") ? "image" : key === "logoHeight" ? "length" : "text",
|
|
188
|
+
impact: BRANDING_KEYS.indexOf(key),
|
|
189
|
+
})),
|
|
190
|
+
];
|
|
90
191
|
function cleanObject(value, keys) {
|
|
91
192
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
92
193
|
return undefined;
|
|
@@ -165,6 +266,13 @@ function toCssVars(colors, sidebar, status, charts, typography, radius, app) {
|
|
|
165
266
|
return {
|
|
166
267
|
["--background"]: colors.background,
|
|
167
268
|
["--foreground"]: colors.foreground,
|
|
269
|
+
["--heading"]: colors.heading ?? colors.foreground,
|
|
270
|
+
["--content-heading-1"]: colors.contentHeading1,
|
|
271
|
+
["--content-heading-2"]: colors.contentHeading2,
|
|
272
|
+
["--content-heading-3"]: colors.contentHeading3,
|
|
273
|
+
["--content-heading-4"]: colors.contentHeading4,
|
|
274
|
+
["--content-heading-5"]: colors.contentHeading5,
|
|
275
|
+
["--content-heading-6"]: colors.contentHeading6,
|
|
168
276
|
["--card"]: colors.card,
|
|
169
277
|
["--card-foreground"]: colors.cardForeground,
|
|
170
278
|
["--popover"]: colors.popover,
|
|
@@ -251,7 +359,7 @@ function defaultSidebar(colors) {
|
|
|
251
359
|
sidebarAccentForeground: colors.accentForeground,
|
|
252
360
|
sidebarSelected: colors.muted,
|
|
253
361
|
sidebarSelectedForeground: colors.foreground,
|
|
254
|
-
sidebarIcon:
|
|
362
|
+
sidebarIcon: "color-mix(in srgb, var(--sidebar-foreground) 60%, transparent)",
|
|
255
363
|
sidebarBorder: colors.border,
|
|
256
364
|
sidebarRing: colors.ring,
|
|
257
365
|
};
|
|
@@ -322,8 +430,8 @@ function defaultApp(mode, colors) {
|
|
|
322
430
|
workflowDiagramSkippedFill: "color-mix(in srgb, var(--muted) 80%, var(--background) 20%)",
|
|
323
431
|
workflowDiagramSkippedStroke: "color-mix(in srgb, var(--muted-foreground) 36%, transparent)",
|
|
324
432
|
workflowDiagramSkippedText: colors.mutedForeground,
|
|
325
|
-
workflowDiagramGlow: "
|
|
326
|
-
workflowDiagramShell: "
|
|
433
|
+
workflowDiagramGlow: "color-mix(in srgb, var(--primary) 18%, transparent)",
|
|
434
|
+
workflowDiagramShell: "color-mix(in srgb, var(--primary) 6%, transparent)",
|
|
327
435
|
};
|
|
328
436
|
}
|
|
329
437
|
return {
|
|
@@ -344,8 +452,8 @@ function defaultApp(mode, colors) {
|
|
|
344
452
|
workflowDiagramSkippedFill: "color-mix(in srgb, var(--muted) 65%, var(--background) 35%)",
|
|
345
453
|
workflowDiagramSkippedStroke: "color-mix(in srgb, var(--muted-foreground) 22%, transparent)",
|
|
346
454
|
workflowDiagramSkippedText: colors.mutedForeground,
|
|
347
|
-
workflowDiagramGlow: "
|
|
348
|
-
workflowDiagramShell: "
|
|
455
|
+
workflowDiagramGlow: "color-mix(in srgb, var(--primary) 18%, transparent)",
|
|
456
|
+
workflowDiagramShell: "color-mix(in srgb, var(--primary) 4%, transparent)",
|
|
349
457
|
};
|
|
350
458
|
}
|
|
351
459
|
export const FOUNDRY_VIOLET_THEME = {
|
|
@@ -437,42 +545,114 @@ export function getThemePreset(name) {
|
|
|
437
545
|
return FOUNDRY_VIOLET_THEME;
|
|
438
546
|
return FOUNDRY_VIOLET_THEME;
|
|
439
547
|
}
|
|
548
|
+
function deriveSurfaceColors(resolved, explicit) {
|
|
549
|
+
// The preset remains the safe fallback for an entirely unthemed product.
|
|
550
|
+
// Only values depending on an authored colour should move. A sparse edit
|
|
551
|
+
// to an unrelated slot must not repaint preset surfaces.
|
|
552
|
+
const changed = new Set(Object.keys(explicit ?? {}).filter((key) => Boolean(explicit?.[key])));
|
|
553
|
+
if (!explicit || changed.size === 0)
|
|
554
|
+
return { colors: resolved, changed };
|
|
555
|
+
const next = { ...resolved, ...explicit };
|
|
556
|
+
const setDerived = (key, value, sources) => {
|
|
557
|
+
if (!explicit[key] && value && sources.some((source) => changed.has(source))) {
|
|
558
|
+
next[key] = value;
|
|
559
|
+
changed.add(key);
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
setDerived("heading", next.foreground, ["foreground"]);
|
|
563
|
+
setDerived("contentHeading1", next.heading, ["heading"]);
|
|
564
|
+
setDerived("contentHeading2", `color-mix(in srgb, ${next.heading} 78%, ${next.foreground} 22%)`, [
|
|
565
|
+
"heading",
|
|
566
|
+
"foreground",
|
|
567
|
+
]);
|
|
568
|
+
setDerived("contentHeading3", next.foreground, ["foreground"]);
|
|
569
|
+
setDerived("contentHeading4", next.foreground, ["foreground"]);
|
|
570
|
+
setDerived("contentHeading5", next.foreground, ["foreground"]);
|
|
571
|
+
setDerived("contentHeading6", next.foreground, ["foreground"]);
|
|
572
|
+
setDerived("card", next.background, ["background"]);
|
|
573
|
+
setDerived("cardForeground", next.foreground, ["foreground"]);
|
|
574
|
+
setDerived("popover", next.card, ["card"]);
|
|
575
|
+
setDerived("popoverForeground", next.foreground, ["foreground"]);
|
|
576
|
+
setDerived("secondary", `color-mix(in srgb, ${next.background} 94%, ${next.primary} 6%)`, [
|
|
577
|
+
"background",
|
|
578
|
+
"primary",
|
|
579
|
+
]);
|
|
580
|
+
setDerived("secondaryForeground", next.foreground, ["foreground"]);
|
|
581
|
+
setDerived("muted", `color-mix(in srgb, ${next.background} 97%, ${next.foreground} 3%)`, [
|
|
582
|
+
"background",
|
|
583
|
+
"foreground",
|
|
584
|
+
]);
|
|
585
|
+
setDerived("mutedForeground", `color-mix(in srgb, ${next.foreground} 62%, ${next.background} 38%)`, ["foreground", "background"]);
|
|
586
|
+
setDerived("accent", `color-mix(in srgb, ${next.background} 90%, ${next.primary} 10%)`, [
|
|
587
|
+
"background",
|
|
588
|
+
"primary",
|
|
589
|
+
]);
|
|
590
|
+
setDerived("accentForeground", next.foreground, ["foreground"]);
|
|
591
|
+
setDerived("border", `color-mix(in srgb, ${next.foreground} 14%, ${next.background} 86%)`, [
|
|
592
|
+
"foreground",
|
|
593
|
+
"background",
|
|
594
|
+
]);
|
|
595
|
+
setDerived("input", next.border, ["border"]);
|
|
596
|
+
setDerived("ring", next.primary, ["primary"]);
|
|
597
|
+
return { colors: next, changed };
|
|
598
|
+
}
|
|
440
599
|
export function resolveThemeRuntime(layers, mode) {
|
|
441
600
|
const effectiveMode = getEffectiveThemeMode(mode);
|
|
442
601
|
const basePreset = layers.find((layer) => layer.basePreset && layer.basePreset.trim())?.basePreset ??
|
|
443
602
|
"foundry-violet";
|
|
444
|
-
const
|
|
603
|
+
const customDefinition = mergeThemeDefinitions(...layers.map((layer) => layer.definition));
|
|
604
|
+
const definitions = [getThemePreset(basePreset), customDefinition];
|
|
445
605
|
const definition = mergeThemeDefinitions(...definitions);
|
|
446
|
-
const colors = {
|
|
447
|
-
|
|
606
|
+
const { colors, changed } = deriveSurfaceColors({ ...(effectiveMode === "dark" ? definition.dark : definition.light) }, effectiveMode === "dark" ? customDefinition.dark : customDefinition.light);
|
|
607
|
+
const explicitSidebar = effectiveMode === "dark" ? customDefinition.sidebar?.dark : customDefinition.sidebar?.light;
|
|
608
|
+
const presetSidebar = effectiveMode === "dark"
|
|
609
|
+
? getThemePreset(basePreset).sidebar?.dark
|
|
610
|
+
: getThemePreset(basePreset).sidebar?.light;
|
|
611
|
+
const sidebarSources = {
|
|
612
|
+
sidebar: "secondary",
|
|
613
|
+
sidebarForeground: "foreground",
|
|
614
|
+
sidebarPrimary: "primary",
|
|
615
|
+
sidebarPrimaryForeground: "primaryForeground",
|
|
616
|
+
sidebarAccent: "accent",
|
|
617
|
+
sidebarAccentForeground: "accentForeground",
|
|
618
|
+
sidebarSelected: "muted",
|
|
619
|
+
sidebarSelectedForeground: "foreground",
|
|
620
|
+
sidebarIcon: null,
|
|
621
|
+
sidebarBorder: "border",
|
|
622
|
+
sidebarRing: "ring",
|
|
448
623
|
};
|
|
624
|
+
const derivedSidebar = defaultSidebar(colors);
|
|
449
625
|
const sidebar = {
|
|
450
|
-
...
|
|
451
|
-
...
|
|
626
|
+
...derivedSidebar,
|
|
627
|
+
...presetSidebar,
|
|
628
|
+
...Object.fromEntries(Object.keys(sidebarSources)
|
|
629
|
+
.filter((key) => sidebarSources[key] && changed.has(sidebarSources[key]))
|
|
630
|
+
.map((key) => [key, derivedSidebar[key]])),
|
|
631
|
+
...explicitSidebar,
|
|
452
632
|
};
|
|
453
633
|
const status = {
|
|
454
634
|
...defaultStatus(effectiveMode, colors),
|
|
455
|
-
...(effectiveMode === "dark" ?
|
|
635
|
+
...(effectiveMode === "dark" ? customDefinition.status?.dark : customDefinition.status?.light),
|
|
456
636
|
};
|
|
457
637
|
const charts = {
|
|
458
638
|
...defaultCharts(effectiveMode),
|
|
459
|
-
...(effectiveMode === "dark" ?
|
|
639
|
+
...(effectiveMode === "dark" ? customDefinition.charts?.dark : customDefinition.charts?.light),
|
|
460
640
|
};
|
|
461
641
|
const typography = {
|
|
462
642
|
...FOUNDRY_VIOLET_THEME.typography,
|
|
463
|
-
...
|
|
643
|
+
...customDefinition.typography,
|
|
464
644
|
};
|
|
465
645
|
const radius = {
|
|
466
646
|
...FOUNDRY_VIOLET_THEME.radius,
|
|
467
|
-
...
|
|
647
|
+
...customDefinition.radius,
|
|
468
648
|
};
|
|
469
649
|
const app = {
|
|
470
650
|
...defaultApp(effectiveMode, colors),
|
|
471
|
-
...(effectiveMode === "dark" ?
|
|
651
|
+
...(effectiveMode === "dark" ? customDefinition.app?.dark : customDefinition.app?.light),
|
|
472
652
|
};
|
|
473
653
|
const branding = {
|
|
474
654
|
...FOUNDRY_VIOLET_THEME.branding,
|
|
475
|
-
...
|
|
655
|
+
...customDefinition.branding,
|
|
476
656
|
};
|
|
477
657
|
return {
|
|
478
658
|
mode: effectiveMode,
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
export type ThemeMode = "light" | "dark" | "system";
|
|
8
8
|
interface ThemeState {
|
|
9
9
|
mode: ThemeMode;
|
|
10
|
-
setMode: (mode: ThemeMode
|
|
10
|
+
setMode: (mode: ThemeMode, options?: {
|
|
11
|
+
persist?: boolean;
|
|
12
|
+
}) => void;
|
|
11
13
|
/** Cycle through light -> dark -> system. */
|
|
12
14
|
cycle: () => void;
|
|
13
15
|
}
|
package/dist/lib/theme-store.js
CHANGED
|
@@ -38,8 +38,9 @@ export const useThemeStore = create((set, get) => {
|
|
|
38
38
|
}
|
|
39
39
|
return {
|
|
40
40
|
mode: initial,
|
|
41
|
-
setMode: (mode) => {
|
|
42
|
-
|
|
41
|
+
setMode: (mode, options) => {
|
|
42
|
+
if (options?.persist !== false)
|
|
43
|
+
localStorage.setItem(STORAGE_KEY, mode);
|
|
43
44
|
applyTheme(mode);
|
|
44
45
|
set({ mode });
|
|
45
46
|
},
|
package/dist/styles.css
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
@theme inline {
|
|
2
|
+
--color-heading: var(--heading, var(--foreground));
|
|
3
|
+
--color-content-heading-1: var(--content-heading-1, var(--heading, var(--foreground)));
|
|
4
|
+
--color-content-heading-2: var(--content-heading-2, var(--heading, var(--foreground)));
|
|
5
|
+
--color-content-heading-3: var(--content-heading-3, var(--foreground));
|
|
6
|
+
--color-content-heading-4: var(--content-heading-4, var(--foreground));
|
|
7
|
+
--color-content-heading-5: var(--content-heading-5, var(--foreground));
|
|
8
|
+
--color-content-heading-6: var(--content-heading-6, var(--foreground));
|
|
2
9
|
--radius-xs: calc(var(--radius) - 6px);
|
|
3
10
|
--radius-sm: calc(var(--radius) - 4px);
|
|
4
11
|
--radius-md: calc(var(--radius) - 2px);
|
|
@@ -255,3 +262,10 @@ tr[data-state="selected"] > [data-pinned="cell"] {
|
|
|
255
262
|
tr[data-active] > [data-pinned="cell"] {
|
|
256
263
|
background-color: color-mix(in srgb, var(--primary) 8%, var(--pinned-surface));
|
|
257
264
|
}
|
|
265
|
+
|
|
266
|
+
@layer base {
|
|
267
|
+
:where(h1, h2, h3, h4, h5, h6) {
|
|
268
|
+
color: var(--heading, var(--foreground));
|
|
269
|
+
font-family: var(--font-heading, inherit);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
@@ -60,12 +60,9 @@ export function SelectionBridge({ children }) {
|
|
|
60
60
|
.workbench-preview [data-sidebar-surface="desktop"] nav { padding-right: 16px; }
|
|
61
61
|
.workbench-preview [data-sidebar-surface="desktop"] { border-right-color: transparent; }
|
|
62
62
|
[data-connected-navigation="true"] [data-sidebar-surface="desktop"] [data-active-nav-row="true"] {
|
|
63
|
-
background: var(--background);
|
|
64
63
|
border-color: transparent; border-top-right-radius: 0; border-bottom-right-radius: 0;
|
|
65
64
|
}
|
|
66
|
-
` }), children, anchor && (
|
|
67
|
-
H ${anchor.rowRight} V ${anchor.top + anchor.height} H ${anchor.width - 8}
|
|
68
|
-
Q ${anchor.width},${anchor.top + anchor.height} ${anchor.width},${anchor.top + anchor.height + 7} Z` }), _jsx("path", { fill: "none", stroke: "var(--sidebar-ring)", strokeOpacity: 0.28, strokeWidth: 1, d: `M ${anchor.width + 12},0.5
|
|
65
|
+
` }), children, anchor && (_jsx("svg", { "aria-hidden": "true", className: "pointer-events-none absolute z-20", style: { inset: 0, width: anchor.width + anchor.surfaceWidth, height: anchor.navHeight }, viewBox: `0 0 ${anchor.width + anchor.surfaceWidth} ${anchor.navHeight}`, children: _jsx("path", { fill: "none", stroke: "var(--sidebar-ring)", strokeOpacity: 0.6, strokeWidth: 1, d: `M ${anchor.width + 12},0.5
|
|
69
66
|
H ${anchor.width + anchor.surfaceWidth - 12}
|
|
70
67
|
Q ${anchor.width + anchor.surfaceWidth - 0.5},0.5 ${anchor.width + anchor.surfaceWidth - 0.5},12
|
|
71
68
|
V ${anchor.navHeight - 12}
|
|
@@ -80,5 +77,5 @@ export function SelectionBridge({ children }) {
|
|
|
80
77
|
Q ${anchor.left},${anchor.top + 0.5} ${anchor.left + 12},${anchor.top + 0.5}
|
|
81
78
|
H ${anchor.width - 8}
|
|
82
79
|
Q ${anchor.width - 0.5},${anchor.top + 0.5} ${anchor.width - 0.5},${anchor.top - 7}
|
|
83
|
-
V 12 Q ${anchor.width - 0.5},0.5 ${anchor.width + 12},0.5 Z` })
|
|
80
|
+
V 12 Q ${anchor.width - 0.5},0.5 ${anchor.width + 12},0.5 Z` }) }))] }));
|
|
84
81
|
}
|
|
@@ -101,7 +101,6 @@ export function WorkbenchStyles() {
|
|
|
101
101
|
}
|
|
102
102
|
.workbench-preview {
|
|
103
103
|
--workbench-header-height: 60px;
|
|
104
|
-
--sidebar: color-mix(in srgb, var(--background) 98.5%, var(--foreground) 1.5%);
|
|
105
104
|
background: var(--sidebar);
|
|
106
105
|
--workbench-outline: color-mix(in srgb, var(--sidebar-ring) 28%, transparent);
|
|
107
106
|
padding: 8px 8px 8px 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iloveagents/foundry-web-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React agent UI core for Foundry UI — chat, composer, AG-UI adapter for assistant-ui, tool cards, panels, sidebar, theme runtime, and UI stores.",
|
|
6
6
|
"keywords": [
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
"recharts": "^3.10.1",
|
|
81
81
|
"remark-gfm": "^4.0.0",
|
|
82
82
|
"tailwind-merge": "^3.5.0",
|
|
83
|
-
"@iloveagents/foundry-agent": "^0.
|
|
84
|
-
"@iloveagents/foundry-web-primitives": "^0.
|
|
83
|
+
"@iloveagents/foundry-agent": "^0.31.0",
|
|
84
|
+
"@iloveagents/foundry-web-primitives": "^0.31.0"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@ag-ui/client": "^0.0.52",
|