@iloveagents/foundry-web-ui 0.30.0 → 0.32.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/theme-runtime-provider.js +33 -0
- 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 +28 -0
- package/dist/lib/theme-runtime.js +213 -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
|
|
@@ -181,10 +181,43 @@ export function ThemeScope({ children, className, style, }) {
|
|
|
181
181
|
}
|
|
182
182
|
export function ThemeDocumentMetadata() {
|
|
183
183
|
const runtime = useThemeRuntime();
|
|
184
|
+
const { faviconUrl, darkFaviconUrl, iconUrl, darkIconUrl, touchIconUrl } = runtime.branding;
|
|
185
|
+
const favicon = runtime.mode === "dark"
|
|
186
|
+
? darkFaviconUrl || faviconUrl || darkIconUrl || iconUrl
|
|
187
|
+
: faviconUrl || darkFaviconUrl || iconUrl || darkIconUrl;
|
|
184
188
|
useEffect(() => {
|
|
185
189
|
if (typeof document === "undefined")
|
|
186
190
|
return;
|
|
187
191
|
document.title = runtime.branding.appTitle || runtime.branding.appName || "Foundry UI";
|
|
188
192
|
}, [runtime.branding.appName, runtime.branding.appTitle]);
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
if (typeof document === "undefined")
|
|
195
|
+
return;
|
|
196
|
+
const managed = [];
|
|
197
|
+
const addIcon = (rel, href) => {
|
|
198
|
+
if (!href)
|
|
199
|
+
return;
|
|
200
|
+
let resolved;
|
|
201
|
+
try {
|
|
202
|
+
resolved = new URL(href, document.baseURI);
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (resolved.protocol !== "http:" &&
|
|
208
|
+
resolved.protocol !== "https:" &&
|
|
209
|
+
!(resolved.protocol === "data:" && /^data:image\//i.test(href)))
|
|
210
|
+
return;
|
|
211
|
+
const link = document.createElement("link");
|
|
212
|
+
link.rel = rel;
|
|
213
|
+
link.href = href;
|
|
214
|
+
link.dataset.themeIcon = "true";
|
|
215
|
+
document.head.appendChild(link);
|
|
216
|
+
managed.push(link);
|
|
217
|
+
};
|
|
218
|
+
addIcon("icon", favicon);
|
|
219
|
+
addIcon("apple-touch-icon", touchIconUrl);
|
|
220
|
+
return () => managed.forEach((link) => link.remove());
|
|
221
|
+
}, [favicon, touchIconUrl]);
|
|
189
222
|
return null;
|
|
190
223
|
}
|
|
@@ -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;
|
|
@@ -109,6 +118,11 @@ export interface ThemeBranding {
|
|
|
109
118
|
*/
|
|
110
119
|
iconUrl?: string;
|
|
111
120
|
darkIconUrl?: string;
|
|
121
|
+
/** Browser tab icon; falls back to the compact brand icon when unset. */
|
|
122
|
+
faviconUrl?: string;
|
|
123
|
+
darkFaviconUrl?: string;
|
|
124
|
+
/** Square PNG recommended for mobile home-screen bookmarks. */
|
|
125
|
+
touchIconUrl?: string;
|
|
112
126
|
/**
|
|
113
127
|
* Rendered height of the mark, as a CSS length (`"2rem"`, `"32px"`).
|
|
114
128
|
* Defaults to the 20px lockup height when unset.
|
|
@@ -161,6 +175,20 @@ export interface ResolvedThemeRuntime {
|
|
|
161
175
|
variables: CSSProperties;
|
|
162
176
|
sources: ThemeLayer[];
|
|
163
177
|
}
|
|
178
|
+
export interface ThemeSlot {
|
|
179
|
+
path: readonly string[];
|
|
180
|
+
label: string;
|
|
181
|
+
group: string;
|
|
182
|
+
kind: "color" | "font" | "length" | "text" | "image";
|
|
183
|
+
cssVariable?: string;
|
|
184
|
+
mode?: "light" | "dark";
|
|
185
|
+
/** Lower values appear first in authoring tools. */
|
|
186
|
+
impact: number;
|
|
187
|
+
/** Human-readable source used when this value is not explicitly set. */
|
|
188
|
+
derivedFrom?: string;
|
|
189
|
+
}
|
|
190
|
+
/** The same allowlists power sanitization and authoring: supported slots cannot disappear from editors. */
|
|
191
|
+
export declare const THEME_SLOTS: readonly ThemeSlot[];
|
|
164
192
|
export declare function mergeThemeDefinitions(...definitions: (ThemeDefinition | null | undefined)[]): ThemeDefinition;
|
|
165
193
|
export declare function getEffectiveThemeMode(mode: ThemeMode): "light" | "dark";
|
|
166
194
|
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
|
];
|
|
@@ -85,8 +92,105 @@ const BRANDING_KEYS = [
|
|
|
85
92
|
"darkLogoUrl",
|
|
86
93
|
"iconUrl",
|
|
87
94
|
"darkIconUrl",
|
|
95
|
+
"faviconUrl",
|
|
96
|
+
"darkFaviconUrl",
|
|
97
|
+
"touchIconUrl",
|
|
88
98
|
"logoHeight",
|
|
89
99
|
];
|
|
100
|
+
const SURFACE_IMPACT = Object.fromEntries(COLOR_KEYS.map((key, index) => [key, index]));
|
|
101
|
+
const SURFACE_DERIVATIONS = {
|
|
102
|
+
heading: "foreground",
|
|
103
|
+
contentHeading1: "interface heading",
|
|
104
|
+
contentHeading2: "interface heading + foreground",
|
|
105
|
+
contentHeading3: "foreground",
|
|
106
|
+
contentHeading4: "foreground",
|
|
107
|
+
contentHeading5: "foreground",
|
|
108
|
+
contentHeading6: "foreground",
|
|
109
|
+
card: "background",
|
|
110
|
+
cardForeground: "foreground",
|
|
111
|
+
popover: "card",
|
|
112
|
+
popoverForeground: "foreground",
|
|
113
|
+
secondary: "background + primary",
|
|
114
|
+
secondaryForeground: "foreground",
|
|
115
|
+
muted: "background + foreground",
|
|
116
|
+
mutedForeground: "foreground + background",
|
|
117
|
+
accent: "background + primary",
|
|
118
|
+
accentForeground: "foreground",
|
|
119
|
+
border: "foreground + background",
|
|
120
|
+
input: "border",
|
|
121
|
+
ring: "primary",
|
|
122
|
+
};
|
|
123
|
+
const cssName = (key) => `--${key.replace(/[A-Z0-9]/g, (part) => `-${part.toLowerCase()}`)}`;
|
|
124
|
+
const slotLabel = (key) => ({
|
|
125
|
+
heading: "Interface headings",
|
|
126
|
+
contentHeading1: "H1",
|
|
127
|
+
contentHeading2: "H2",
|
|
128
|
+
contentHeading3: "H3",
|
|
129
|
+
contentHeading4: "H4",
|
|
130
|
+
contentHeading5: "H5",
|
|
131
|
+
contentHeading6: "H6",
|
|
132
|
+
sidebarSelected: "Selected background",
|
|
133
|
+
sidebarSelectedForeground: "Selected text",
|
|
134
|
+
})[key] ?? key.replace(/([a-z])([A-Z0-9])/g, "$1 $2").replace(/^./, (c) => c.toUpperCase());
|
|
135
|
+
/** The same allowlists power sanitization and authoring: supported slots cannot disappear from editors. */
|
|
136
|
+
export const THEME_SLOTS = [
|
|
137
|
+
...["light", "dark"].flatMap((mode) => [
|
|
138
|
+
...COLOR_KEYS.map((key) => ({
|
|
139
|
+
path: [mode, key],
|
|
140
|
+
label: slotLabel(key),
|
|
141
|
+
group: key.startsWith("contentHeading") ? "Content" : "Surfaces",
|
|
142
|
+
kind: "color",
|
|
143
|
+
cssVariable: cssName(key),
|
|
144
|
+
mode,
|
|
145
|
+
impact: SURFACE_IMPACT[key],
|
|
146
|
+
derivedFrom: SURFACE_DERIVATIONS[key],
|
|
147
|
+
})),
|
|
148
|
+
...[
|
|
149
|
+
["sidebar", SIDEBAR_KEYS, "Navigation"],
|
|
150
|
+
["status", STATUS_KEYS, "Signals"],
|
|
151
|
+
["charts", CHART_KEYS, "Charts"],
|
|
152
|
+
["app", APP_KEYS, "Code & workflows"],
|
|
153
|
+
].flatMap(([section, keys, group]) => keys.map((key, impact) => ({
|
|
154
|
+
path: [section, mode, key],
|
|
155
|
+
label: slotLabel(key),
|
|
156
|
+
group,
|
|
157
|
+
kind: "color",
|
|
158
|
+
cssVariable: cssName(key),
|
|
159
|
+
mode,
|
|
160
|
+
impact,
|
|
161
|
+
derivedFrom: group === "Navigation"
|
|
162
|
+
? "page colours"
|
|
163
|
+
: group === "Signals" && String(key).startsWith("info")
|
|
164
|
+
? "primary action"
|
|
165
|
+
: group === "Code & workflows"
|
|
166
|
+
? "page and signal colours"
|
|
167
|
+
: undefined,
|
|
168
|
+
}))),
|
|
169
|
+
]),
|
|
170
|
+
...TYPOGRAPHY_KEYS.map((key) => ({
|
|
171
|
+
path: ["typography", key],
|
|
172
|
+
label: slotLabel(key),
|
|
173
|
+
group: "Typography & shape",
|
|
174
|
+
kind: "font",
|
|
175
|
+
cssVariable: `--font-${key.replace("Font", "")}`,
|
|
176
|
+
impact: key === "headingFont" ? 0 : key === "bodyFont" ? 1 : 3,
|
|
177
|
+
})),
|
|
178
|
+
...RADIUS_KEYS.map((key) => ({
|
|
179
|
+
path: ["radius", key],
|
|
180
|
+
label: "Corner radius",
|
|
181
|
+
group: "Typography & shape",
|
|
182
|
+
kind: "length",
|
|
183
|
+
cssVariable: cssName(key),
|
|
184
|
+
impact: 2,
|
|
185
|
+
})),
|
|
186
|
+
...BRANDING_KEYS.map((key) => ({
|
|
187
|
+
path: ["branding", key],
|
|
188
|
+
label: slotLabel(key),
|
|
189
|
+
group: "Brand",
|
|
190
|
+
kind: key.endsWith("Url") ? "image" : key === "logoHeight" ? "length" : "text",
|
|
191
|
+
impact: BRANDING_KEYS.indexOf(key),
|
|
192
|
+
})),
|
|
193
|
+
];
|
|
90
194
|
function cleanObject(value, keys) {
|
|
91
195
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
92
196
|
return undefined;
|
|
@@ -165,6 +269,13 @@ function toCssVars(colors, sidebar, status, charts, typography, radius, app) {
|
|
|
165
269
|
return {
|
|
166
270
|
["--background"]: colors.background,
|
|
167
271
|
["--foreground"]: colors.foreground,
|
|
272
|
+
["--heading"]: colors.heading ?? colors.foreground,
|
|
273
|
+
["--content-heading-1"]: colors.contentHeading1,
|
|
274
|
+
["--content-heading-2"]: colors.contentHeading2,
|
|
275
|
+
["--content-heading-3"]: colors.contentHeading3,
|
|
276
|
+
["--content-heading-4"]: colors.contentHeading4,
|
|
277
|
+
["--content-heading-5"]: colors.contentHeading5,
|
|
278
|
+
["--content-heading-6"]: colors.contentHeading6,
|
|
168
279
|
["--card"]: colors.card,
|
|
169
280
|
["--card-foreground"]: colors.cardForeground,
|
|
170
281
|
["--popover"]: colors.popover,
|
|
@@ -251,7 +362,7 @@ function defaultSidebar(colors) {
|
|
|
251
362
|
sidebarAccentForeground: colors.accentForeground,
|
|
252
363
|
sidebarSelected: colors.muted,
|
|
253
364
|
sidebarSelectedForeground: colors.foreground,
|
|
254
|
-
sidebarIcon:
|
|
365
|
+
sidebarIcon: "color-mix(in srgb, var(--sidebar-foreground) 60%, transparent)",
|
|
255
366
|
sidebarBorder: colors.border,
|
|
256
367
|
sidebarRing: colors.ring,
|
|
257
368
|
};
|
|
@@ -322,8 +433,8 @@ function defaultApp(mode, colors) {
|
|
|
322
433
|
workflowDiagramSkippedFill: "color-mix(in srgb, var(--muted) 80%, var(--background) 20%)",
|
|
323
434
|
workflowDiagramSkippedStroke: "color-mix(in srgb, var(--muted-foreground) 36%, transparent)",
|
|
324
435
|
workflowDiagramSkippedText: colors.mutedForeground,
|
|
325
|
-
workflowDiagramGlow: "
|
|
326
|
-
workflowDiagramShell: "
|
|
436
|
+
workflowDiagramGlow: "color-mix(in srgb, var(--primary) 18%, transparent)",
|
|
437
|
+
workflowDiagramShell: "color-mix(in srgb, var(--primary) 6%, transparent)",
|
|
327
438
|
};
|
|
328
439
|
}
|
|
329
440
|
return {
|
|
@@ -344,8 +455,8 @@ function defaultApp(mode, colors) {
|
|
|
344
455
|
workflowDiagramSkippedFill: "color-mix(in srgb, var(--muted) 65%, var(--background) 35%)",
|
|
345
456
|
workflowDiagramSkippedStroke: "color-mix(in srgb, var(--muted-foreground) 22%, transparent)",
|
|
346
457
|
workflowDiagramSkippedText: colors.mutedForeground,
|
|
347
|
-
workflowDiagramGlow: "
|
|
348
|
-
workflowDiagramShell: "
|
|
458
|
+
workflowDiagramGlow: "color-mix(in srgb, var(--primary) 18%, transparent)",
|
|
459
|
+
workflowDiagramShell: "color-mix(in srgb, var(--primary) 4%, transparent)",
|
|
349
460
|
};
|
|
350
461
|
}
|
|
351
462
|
export const FOUNDRY_VIOLET_THEME = {
|
|
@@ -437,42 +548,114 @@ export function getThemePreset(name) {
|
|
|
437
548
|
return FOUNDRY_VIOLET_THEME;
|
|
438
549
|
return FOUNDRY_VIOLET_THEME;
|
|
439
550
|
}
|
|
551
|
+
function deriveSurfaceColors(resolved, explicit) {
|
|
552
|
+
// The preset remains the safe fallback for an entirely unthemed product.
|
|
553
|
+
// Only values depending on an authored colour should move. A sparse edit
|
|
554
|
+
// to an unrelated slot must not repaint preset surfaces.
|
|
555
|
+
const changed = new Set(Object.keys(explicit ?? {}).filter((key) => Boolean(explicit?.[key])));
|
|
556
|
+
if (!explicit || changed.size === 0)
|
|
557
|
+
return { colors: resolved, changed };
|
|
558
|
+
const next = { ...resolved, ...explicit };
|
|
559
|
+
const setDerived = (key, value, sources) => {
|
|
560
|
+
if (!explicit[key] && value && sources.some((source) => changed.has(source))) {
|
|
561
|
+
next[key] = value;
|
|
562
|
+
changed.add(key);
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
setDerived("heading", next.foreground, ["foreground"]);
|
|
566
|
+
setDerived("contentHeading1", next.heading, ["heading"]);
|
|
567
|
+
setDerived("contentHeading2", `color-mix(in srgb, ${next.heading} 78%, ${next.foreground} 22%)`, [
|
|
568
|
+
"heading",
|
|
569
|
+
"foreground",
|
|
570
|
+
]);
|
|
571
|
+
setDerived("contentHeading3", next.foreground, ["foreground"]);
|
|
572
|
+
setDerived("contentHeading4", next.foreground, ["foreground"]);
|
|
573
|
+
setDerived("contentHeading5", next.foreground, ["foreground"]);
|
|
574
|
+
setDerived("contentHeading6", next.foreground, ["foreground"]);
|
|
575
|
+
setDerived("card", next.background, ["background"]);
|
|
576
|
+
setDerived("cardForeground", next.foreground, ["foreground"]);
|
|
577
|
+
setDerived("popover", next.card, ["card"]);
|
|
578
|
+
setDerived("popoverForeground", next.foreground, ["foreground"]);
|
|
579
|
+
setDerived("secondary", `color-mix(in srgb, ${next.background} 94%, ${next.primary} 6%)`, [
|
|
580
|
+
"background",
|
|
581
|
+
"primary",
|
|
582
|
+
]);
|
|
583
|
+
setDerived("secondaryForeground", next.foreground, ["foreground"]);
|
|
584
|
+
setDerived("muted", `color-mix(in srgb, ${next.background} 97%, ${next.foreground} 3%)`, [
|
|
585
|
+
"background",
|
|
586
|
+
"foreground",
|
|
587
|
+
]);
|
|
588
|
+
setDerived("mutedForeground", `color-mix(in srgb, ${next.foreground} 62%, ${next.background} 38%)`, ["foreground", "background"]);
|
|
589
|
+
setDerived("accent", `color-mix(in srgb, ${next.background} 90%, ${next.primary} 10%)`, [
|
|
590
|
+
"background",
|
|
591
|
+
"primary",
|
|
592
|
+
]);
|
|
593
|
+
setDerived("accentForeground", next.foreground, ["foreground"]);
|
|
594
|
+
setDerived("border", `color-mix(in srgb, ${next.foreground} 14%, ${next.background} 86%)`, [
|
|
595
|
+
"foreground",
|
|
596
|
+
"background",
|
|
597
|
+
]);
|
|
598
|
+
setDerived("input", next.border, ["border"]);
|
|
599
|
+
setDerived("ring", next.primary, ["primary"]);
|
|
600
|
+
return { colors: next, changed };
|
|
601
|
+
}
|
|
440
602
|
export function resolveThemeRuntime(layers, mode) {
|
|
441
603
|
const effectiveMode = getEffectiveThemeMode(mode);
|
|
442
604
|
const basePreset = layers.find((layer) => layer.basePreset && layer.basePreset.trim())?.basePreset ??
|
|
443
605
|
"foundry-violet";
|
|
444
|
-
const
|
|
606
|
+
const customDefinition = mergeThemeDefinitions(...layers.map((layer) => layer.definition));
|
|
607
|
+
const definitions = [getThemePreset(basePreset), customDefinition];
|
|
445
608
|
const definition = mergeThemeDefinitions(...definitions);
|
|
446
|
-
const colors = {
|
|
447
|
-
|
|
609
|
+
const { colors, changed } = deriveSurfaceColors({ ...(effectiveMode === "dark" ? definition.dark : definition.light) }, effectiveMode === "dark" ? customDefinition.dark : customDefinition.light);
|
|
610
|
+
const explicitSidebar = effectiveMode === "dark" ? customDefinition.sidebar?.dark : customDefinition.sidebar?.light;
|
|
611
|
+
const presetSidebar = effectiveMode === "dark"
|
|
612
|
+
? getThemePreset(basePreset).sidebar?.dark
|
|
613
|
+
: getThemePreset(basePreset).sidebar?.light;
|
|
614
|
+
const sidebarSources = {
|
|
615
|
+
sidebar: "secondary",
|
|
616
|
+
sidebarForeground: "foreground",
|
|
617
|
+
sidebarPrimary: "primary",
|
|
618
|
+
sidebarPrimaryForeground: "primaryForeground",
|
|
619
|
+
sidebarAccent: "accent",
|
|
620
|
+
sidebarAccentForeground: "accentForeground",
|
|
621
|
+
sidebarSelected: "muted",
|
|
622
|
+
sidebarSelectedForeground: "foreground",
|
|
623
|
+
sidebarIcon: null,
|
|
624
|
+
sidebarBorder: "border",
|
|
625
|
+
sidebarRing: "ring",
|
|
448
626
|
};
|
|
627
|
+
const derivedSidebar = defaultSidebar(colors);
|
|
449
628
|
const sidebar = {
|
|
450
|
-
...
|
|
451
|
-
...
|
|
629
|
+
...derivedSidebar,
|
|
630
|
+
...presetSidebar,
|
|
631
|
+
...Object.fromEntries(Object.keys(sidebarSources)
|
|
632
|
+
.filter((key) => sidebarSources[key] && changed.has(sidebarSources[key]))
|
|
633
|
+
.map((key) => [key, derivedSidebar[key]])),
|
|
634
|
+
...explicitSidebar,
|
|
452
635
|
};
|
|
453
636
|
const status = {
|
|
454
637
|
...defaultStatus(effectiveMode, colors),
|
|
455
|
-
...(effectiveMode === "dark" ?
|
|
638
|
+
...(effectiveMode === "dark" ? customDefinition.status?.dark : customDefinition.status?.light),
|
|
456
639
|
};
|
|
457
640
|
const charts = {
|
|
458
641
|
...defaultCharts(effectiveMode),
|
|
459
|
-
...(effectiveMode === "dark" ?
|
|
642
|
+
...(effectiveMode === "dark" ? customDefinition.charts?.dark : customDefinition.charts?.light),
|
|
460
643
|
};
|
|
461
644
|
const typography = {
|
|
462
645
|
...FOUNDRY_VIOLET_THEME.typography,
|
|
463
|
-
...
|
|
646
|
+
...customDefinition.typography,
|
|
464
647
|
};
|
|
465
648
|
const radius = {
|
|
466
649
|
...FOUNDRY_VIOLET_THEME.radius,
|
|
467
|
-
...
|
|
650
|
+
...customDefinition.radius,
|
|
468
651
|
};
|
|
469
652
|
const app = {
|
|
470
653
|
...defaultApp(effectiveMode, colors),
|
|
471
|
-
...(effectiveMode === "dark" ?
|
|
654
|
+
...(effectiveMode === "dark" ? customDefinition.app?.dark : customDefinition.app?.light),
|
|
472
655
|
};
|
|
473
656
|
const branding = {
|
|
474
657
|
...FOUNDRY_VIOLET_THEME.branding,
|
|
475
|
-
...
|
|
658
|
+
...customDefinition.branding,
|
|
476
659
|
};
|
|
477
660
|
return {
|
|
478
661
|
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.32.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.32.0",
|
|
84
|
+
"@iloveagents/foundry-web-primitives": "^0.32.0"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@ag-ui/client": "^0.0.52",
|