UI Providers¶
Singleton context providers that power shared UI systems — context menus, galleries, popovers, and navigation state. Most are already mounted in ClientProviders; only PopoverProvider, MenuProvider, PredictionContextMenuProvider, and PredictionDropdownProvider require local placement.
Provider Map¶
| Provider | Global? | Hook | Purpose |
|---|---|---|---|
ActionMenuProvider |
yes | useActionMenu() |
Programmatic context menu rendered as a portal |
MediaResourceGalleryProvider |
yes | useMediaResourceGallery() |
Lightbox gallery for MediaResourceRenderer |
FloatingWindowProvider |
yes | useFloatingWindow() |
Draggable/resizable floating panels |
ModalProvider |
yes | useModal(), useInlineModal() |
Modal stack |
PopoverProvider |
no | usePopoverProvider() |
Single-active-popover within a subtree |
MenuProvider |
no | useMenu() |
Sidebar collapsed/expanded state |
PredictionContextMenuProvider |
no | usePredictionContextMenu() |
Context menu for generation prediction cards |
PredictionDropdownProvider |
no | usePredictionDropdown() |
Dropdown for generation prediction cards |
"Global" means mounted once in ClientProviders — no per-page setup needed.
ActionMenuProvider + useActionMenu()¶
Global singleton. Renders the menu as a createPortal to document.body.
import { useActionMenu } from "@/providers/ActionMenuProvider";
const menu = useActionMenu();
menu.open(event, { actions, context: myEntity });
menu.close();
menu.isOpen; // boolean
open(position, options)— position can be aMouseEvent,KeyboardEvent, or{ x, y }coordinates- Menu auto-repositions to stay within the viewport (estimates 200×300 px)
contextinOpenMenuOptionsmaps toctx.datainside action handlers- Auto-closes on outside left-click, scroll (outside the menu), resize, and Escape
- Async
onSelectshows a per-item loading spinner; errors surface as a toast confirmon aStandardActionshows anAlertDialogbefore executing
See Action Menu for the full Action<T> type reference.
Source: src/providers/ActionMenuProvider.tsx
MediaResourceGalleryProvider + useMediaResourceGallery()¶
Global singleton. Powers the lightbox opened when clicking a MediaResourceRenderer.
import { useMediaResourceGallery } from "@/providers/MediaResourceGalleryProvider";
const gallery = useMediaResourceGallery(); // returns null outside provider
| Method | Description |
|---|---|
register(galleryKey, resource) |
Add a resource to a named gallery group |
unregister(galleryKey, resourceId) |
Remove a resource from a group |
open(galleryKey, resource, options?) |
Open the lightbox at the given resource |
close() |
Close the topmost gallery layer |
isOpen |
boolean |
layerCount |
Number of stacked gallery layers currently open |
Stacking: galleries push onto a layer stack. Opening the same galleryKey again updates the selected resource in place instead of adding a new layer.
OpenGalleryOptions:
| Prop | Type | Description |
|---|---|---|
leftSidebar |
ReactNode |
Custom left sidebar content inside the lightbox |
additionalActions |
ReactNode |
Extra footer actions |
MediaResourceRenderer calls gallery.register on mount and gallery.unregister on unmount automatically. You do not call these methods directly unless building a custom gallery consumer.
useMediaResourceGallery() returns null gracefully outside the provider. Use useMediaResourceGalleryRequired() if you need to throw on missing context.
Source: src/providers/MediaResourceGalleryProvider.tsx
PopoverProvider + usePopoverProvider()¶
Local provider — mount it around any subtree that needs only one popover open at a time. Not a global singleton.
import {
PopoverProvider,
usePopoverProvider,
ManagedPopover,
} from "@/providers/PopoverProvider";
// Wrap the subtree
<PopoverProvider>
<CommentPinList />
</PopoverProvider>
// Inside a child — open/close by ID
const { open, close, isOpen, activeId } = usePopoverProvider();
open("pin-42"); // closes any other open popover in this subtree
isOpen("pin-42"); // true
close(); // closes the active popover
ManagedPopover component¶
Convenience wrapper that wires a Radix Popover to the provider:
<ManagedPopover
id="pin-42"
content={<CommentPinPopover pin={pin} />}
contentProps={{ side: "top", sideOffset: 8 }}
>
<PinButton onClick={() => open("pin-42")} />
</ManagedPopover>
| Prop | Type | Description |
|---|---|---|
id |
string |
Unique ID in this provider subtree |
content |
ReactNode |
Popover panel content |
children |
ReactNode |
Anchor element |
onClose |
() => void |
Called when the popover closes |
contentProps |
PopoverContentProps |
Passed to Radix PopoverContent |
Used internally by CommentPinOverlay to manage annotation pins on MediaResourceRenderer.
Source: src/providers/PopoverProvider.tsx
MenuProvider + useMenu()¶
Local provider — controls whether the sidebar navigation is collapsed. Mount it around the layout that contains the sidebar.
import { MenuProvider, useMenu } from "@/providers/MenuContext";
// In the layout
<MenuProvider defaultCollapsed={true}>
<Sidebar />
{children}
</MenuProvider>
// In any child
const { isCollapsed, toggleCollapsed } = useMenu();
| Value | Type | Description |
|---|---|---|
isCollapsed |
boolean |
Current collapsed state |
toggleCollapsed |
() => void |
Toggle between collapsed and expanded |
Source: src/providers/MenuContext.tsx
PredictionContextMenuProvider + usePredictionContextMenu()¶
Local provider — singleton context menu for generation prediction cards. Renders one portal at a time; opening a new menu immediately replaces the previous one.
import {
PredictionContextMenuProvider,
usePredictionContextMenu,
} from "@/providers/PredictionContextMenuProvider";
// Mount around the generation grid
<PredictionContextMenuProvider toolbarHidden={false}>
<GenerationGrid />
</PredictionContextMenuProvider>
// Inside a card — open on right-click
const { openContextMenu, closeContextMenu, isOpen } =
usePredictionContextMenu();
openContextMenu(data, { x: e.clientX, y: e.clientY });
ContextMenuData:
| Field | Type | Description |
|---|---|---|
prediction |
PredictionPublic |
The prediction entity |
generation |
Generation |
Parent generation |
shootingLook |
ShootingLookPublic? |
Optional, for subject-swap actions |
imageUrl |
string \| null |
Preview image URL |
predictionShotType |
string? |
Shot type label |
refineOptions |
RefineOption[] |
Available refine actions |
toolsWithInputImage |
any[] |
AI tools that accept this image as input |
hideDelete |
boolean? |
Suppress the delete action |
onDelete |
() => Promise<void> |
Delete callback |
onAIToolClick |
(tool) => void |
AI tool selection callback |
onQuickAction |
(tool) => void |
Quick action callback |
onDownload |
(format) => Promise<void>? |
Download with format selection |
Auto-closes on outside left-click, scroll (outside the menu and Radix portals), resize, and Escape.
Source: src/providers/PredictionContextMenuProvider.tsx
PredictionDropdownProvider + usePredictionDropdown()¶
Local provider — singleton Radix DropdownMenu for generation prediction cards, triggered by a button rather than right-click. Uses a virtual fixed-position trigger anchored to the stored trigger element bounds.
import {
PredictionDropdownProvider,
usePredictionDropdown,
} from "@/providers/PredictionDropdownProvider";
<PredictionDropdownProvider toolbarHidden={false}>
<GenerationGrid />
</PredictionDropdownProvider>
// Inside a card
const { openDropdown, closeDropdown, isOpen } = usePredictionDropdown();
openDropdown(data, buttonElement); // opens anchored to the button
DropdownData is the same shape as ContextMenuData minus shootingLook, onQuickAction, and position — the trigger element provides the anchor.
Auto-closes on outside click, scroll, and resize.
Source: src/providers/PredictionDropdownProvider.tsx
ClientProviders — Global Provider Tree¶
The full nesting order (outermost → innermost):
OrganizationContextProvider
WebSocketProvider
OrganizationProvider
BreadcrumbRegistryProvider
DragProvider
ProductProvider
GalleryFilterProvider (mode="global-persisted", key="main-gallery")
ExportTasksProvider
ModalProvider
FloatingWindowProvider
TooltipProvider
ActionMenuProvider
MediaResourceGalleryProvider
{children}
<UploadProgressDialog />
<ModalOutlet />
<FloatingWindowOutlet />
Source: src/providers/ClientProviders.tsx
Source Files¶
| File | Contents |
|---|---|
src/providers/ClientProviders.tsx |
Global provider tree, queryClient config |
src/providers/ActionMenuProvider.tsx |
Action menu context + portal renderer |
src/providers/MediaResourceGalleryProvider.tsx |
Lightbox gallery context + layer stack |
src/providers/FloatingWindowProvider.tsx |
Floating window context (see Floating Windows) |
src/providers/ModalProvider.tsx |
Modal stack context (see Modals) |
src/providers/PopoverProvider.tsx |
Single-active-popover context + ManagedPopover |
src/providers/MenuContext.tsx |
Sidebar collapsed state |
src/providers/PredictionContextMenuProvider.tsx |
Prediction card right-click menu |
src/providers/PredictionDropdownProvider.tsx |
Prediction card dropdown menu |